Skip to content

Commit

Permalink
JAMES-2037 Offer direct UID retrieval from MessageManager
Browse files Browse the repository at this point in the history
  • Loading branch information
chibenwa authored and aduprat committed Jun 9, 2017
1 parent 3f0aa54 commit e6f33c3
Show file tree
Hide file tree
Showing 14 changed files with 218 additions and 31 deletions.
Expand Up @@ -740,18 +740,6 @@ public static Criterion flagIsUnSet(String flag) {
return new CustomFlagCriterion(flag, BooleanOperator.unset()); return new CustomFlagCriterion(flag, BooleanOperator.unset());
} }


public SearchQuery() {
this(new ArrayList<Criterion>());
}

public SearchQuery(Criterion... criteria) {
this(ImmutableList.copyOf(criteria));
}

public SearchQuery(List<Criterion> criterias) {
this.criterias = criterias;
}

/** /**
* Creates a filter matching all messages. * Creates a filter matching all messages.
* *
Expand All @@ -767,6 +755,18 @@ public static Criterion all() {


private List<Sort> sorts = Collections.singletonList(new Sort(Sort.SortClause.Uid, Sort.Order.NATURAL)); private List<Sort> sorts = Collections.singletonList(new Sort(Sort.SortClause.Uid, Sort.Order.NATURAL));


public SearchQuery(Criterion... criterias) {
this(new ArrayList<Criterion>(Arrays.asList(criterias)));
}

public SearchQuery() {
this(new ArrayList<Criterion>());
}

private SearchQuery(List<Criterion> criterias) {
this.criterias = criterias;
}

public void andCriteria(Criterion crit) { public void andCriteria(Criterion crit) {
criterias.add(crit); criterias.add(crit);
} }
Expand Down Expand Up @@ -827,12 +827,12 @@ public String toString() {
} }


@Override @Override
public int hashCode() { public final int hashCode() {
return Objects.hashCode(criterias); return Objects.hashCode(criterias);
} }


@Override @Override
public boolean equals(Object obj) { public final boolean equals(Object obj) {
if (obj instanceof SearchQuery) { if (obj instanceof SearchQuery) {
SearchQuery that = (SearchQuery) obj; SearchQuery that = (SearchQuery) obj;


Expand Down
@@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/

package org.apache.james.mailbox.model;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Test;

import nl.jqno.equalsverifier.EqualsVerifier;

public class SearchQueryTest {

@Test
public void searchQueryShouldRespectBeanContract() {
EqualsVerifier.forClass(SearchQuery.class).verify();
}

@Test
public void equalsShouldCompareCriteria() {
SearchQuery searchQuery1 = new SearchQuery();
SearchQuery searchQuery2 = new SearchQuery();
searchQuery1.andCriteria(SearchQuery.all());
searchQuery2.andCriteria(SearchQuery.all());

assertThat(searchQuery1).isEqualTo(searchQuery2);
}

}
Expand Up @@ -34,6 +34,11 @@ public CachingMessageMapper(MessageMapper underlying, MailboxMetadataCache cache
this.cache = cache; this.cache = cache;
} }


@Override
public Iterator<MessageUid> listAllMessageUids(Mailbox mailbox) throws MailboxException {
return underlying.listAllMessageUids(mailbox);
}

@Override @Override
public void endRequest() { public void endRequest() {
underlying.endRequest(); underlying.endRequest();
Expand Down
Expand Up @@ -107,6 +107,15 @@ public CassandraMessageMapper(CassandraUidProvider uidProvider, CassandraModSeqP
this.deletedMessageDAO = deletedMessageDAO; this.deletedMessageDAO = deletedMessageDAO;
} }


@Override
public Iterator<MessageUid> listAllMessageUids(Mailbox mailbox) throws MailboxException {
CassandraId cassandraId = (CassandraId) mailbox.getMailboxId();
return messageIdDAO.retrieveMessages(cassandraId, MessageRange.all())
.join()
.map(metaData -> metaData.getComposedMessageId().getUid())
.iterator();
}

@Override @Override
public long countMessagesInMailbox(Mailbox mailbox) throws MailboxException { public long countMessagesInMailbox(Mailbox mailbox) throws MailboxException {
return mailboxCounterDAO.countMessagesInMailbox(mailbox) return mailboxCounterDAO.countMessagesInMailbox(mailbox)
Expand Down
Expand Up @@ -48,6 +48,7 @@
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;


import javax.annotation.Nullable;
import javax.mail.Flags; import javax.mail.Flags;


import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
Expand Down Expand Up @@ -85,8 +86,10 @@
import org.apache.james.mailbox.store.mail.utils.ApplicableFlagCalculator; import org.apache.james.mailbox.store.mail.utils.ApplicableFlagCalculator;
import org.apache.james.mailbox.store.transaction.NonTransactionalMapper; import org.apache.james.mailbox.store.transaction.NonTransactionalMapper;


import com.google.common.base.Function;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;


/** /**
* HBase implementation of a {@link MessageMapper}. * HBase implementation of a {@link MessageMapper}.
Expand All @@ -95,6 +98,14 @@
*/ */
public class HBaseMessageMapper extends NonTransactionalMapper implements MessageMapper { public class HBaseMessageMapper extends NonTransactionalMapper implements MessageMapper {


private static final int UNLIMITED = -1;
private static final Function<MailboxMessage, MessageUid> TO_UID = new Function<MailboxMessage, MessageUid>() {
@Override
public MessageUid apply(MailboxMessage mailboxMessage) {
return mailboxMessage.getUid();
}
};

private final Configuration conf; private final Configuration conf;
private final MailboxSession mailboxSession; private final MailboxSession mailboxSession;
private final UidProvider uidProvider; private final UidProvider uidProvider;
Expand All @@ -121,6 +132,11 @@ public MailboxCounters getMailboxCounters(Mailbox mailbox) throws MailboxExcepti
.build(); .build();
} }


@Override
public Iterator<MessageUid> listAllMessageUids(final Mailbox mailbox) throws MailboxException {
return Iterators.transform(findInMailbox(mailbox, MessageRange.all(), FetchType.Full, UNLIMITED), TO_UID);
}

@Override @Override
public void endRequest() { public void endRequest() {
} }
Expand Down
Expand Up @@ -55,14 +55,24 @@
import org.apache.james.mailbox.store.mail.utils.ApplicableFlagCalculator; import org.apache.james.mailbox.store.mail.utils.ApplicableFlagCalculator;
import org.apache.openjpa.persistence.ArgumentException; import org.apache.openjpa.persistence.ArgumentException;


import com.google.common.base.Function;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;


/** /**
* JPA implementation of a {@link MessageMapper}. This class is not thread-safe! * JPA implementation of a {@link MessageMapper}. This class is not thread-safe!
*/ */
public class JPAMessageMapper extends JPATransactionalMapper implements MessageMapper { public class JPAMessageMapper extends JPATransactionalMapper implements MessageMapper {
private static final int UNLIMIT_MAX_SIZE = -1; private static final int UNLIMIT_MAX_SIZE = -1;
private static final int UNLIMITED = -1;
private static final Function<MailboxMessage, MessageUid> TO_UID = new Function<MailboxMessage, MessageUid>() {
@Override
public MessageUid apply(MailboxMessage mailboxMessage) {
return mailboxMessage.getUid();
}
};

private final MessageUtils messageMetadataMapper; private final MessageUtils messageMetadataMapper;


public JPAMessageMapper(MailboxSession mailboxSession, UidProvider uidProvider, ModSeqProvider modSeqProvider, EntityManagerFactory entityManagerFactory) { public JPAMessageMapper(MailboxSession mailboxSession, UidProvider uidProvider, ModSeqProvider modSeqProvider, EntityManagerFactory entityManagerFactory) {
Expand All @@ -78,6 +88,11 @@ public MailboxCounters getMailboxCounters(Mailbox mailbox) throws MailboxExcepti
.build(); .build();
} }


@Override
public Iterator<MessageUid> listAllMessageUids(final Mailbox mailbox) throws MailboxException {
return Iterators.transform(findInMailbox(mailbox, MessageRange.all(), FetchType.Full, UNLIMITED), TO_UID);
}

/** /**
* @see org.apache.james.mailbox.store.mail.MessageMapper#findInMailbox(org.apache.james.mailbox.store.mail.model.Mailbox, * @see org.apache.james.mailbox.store.mail.MessageMapper#findInMailbox(org.apache.james.mailbox.store.mail.model.Mailbox,
* org.apache.james.mailbox.model.MessageRange, * org.apache.james.mailbox.model.MessageRange,
Expand Down
Expand Up @@ -58,6 +58,11 @@ public MailboxCounters getMailboxCounters(Mailbox mailbox) throws MailboxExcepti
.build(); .build();
} }


@Override
public Iterator<MessageUid> listAllMessageUids(Mailbox mailbox) throws MailboxException {
return messageMapper.listAllMessageUids(mailbox);
}

@Override @Override
public <T> T execute(Transaction<T> transaction) throws MailboxException { public <T> T execute(Transaction<T> transaction) throws MailboxException {
throw new NotImplementedException(); throw new NotImplementedException();
Expand Down
Expand Up @@ -748,6 +748,9 @@ public Map<MessageUid, MessageMetaData> run() throws MailboxException {


@Override @Override
public Iterator<MessageUid> search(SearchQuery query, MailboxSession mailboxSession) throws MailboxException { public Iterator<MessageUid> search(SearchQuery query, MailboxSession mailboxSession) throws MailboxException {
if (query.equals(new SearchQuery(SearchQuery.all()))) {
return listAllMessageUids(mailboxSession);
}
return index.search(mailboxSession, getMailboxEntity(), query); return index.search(mailboxSession, getMailboxEntity(), query);
} }


Expand Down Expand Up @@ -872,4 +875,15 @@ public Flags getApplicableFlags(MailboxSession session) throws MailboxException
return mapperFactory.getMessageMapper(session) return mapperFactory.getMessageMapper(session)
.getApplicableFlag(mailbox); .getApplicableFlag(mailbox);
} }

private Iterator<MessageUid> listAllMessageUids(MailboxSession session) throws MailboxException {
final MessageMapper messageMapper = mapperFactory.getMessageMapper(session);

return messageMapper.execute(new Mapper.Transaction<Iterator<MessageUid>>() {
@Override
public Iterator<MessageUid> run() throws MailboxException {
return messageMapper.listAllMessageUids(mailbox);
}
});
}
} }
Expand Up @@ -36,14 +36,25 @@
import org.apache.james.mailbox.store.mail.model.MailboxMessage; import org.apache.james.mailbox.store.mail.model.MailboxMessage;
import org.apache.james.mailbox.store.transaction.TransactionalMapper; import org.apache.james.mailbox.store.transaction.TransactionalMapper;


import com.google.common.base.Function;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.collect.Iterators;


/** /**
* Abstract base class for {@link MessageMapper} implementation * Abstract base class for {@link MessageMapper} implementation
* which already takes care of most uid / mod-seq handling. * which already takes care of most uid / mod-seq handling.
* *
*/ */
public abstract class AbstractMessageMapper extends TransactionalMapper implements MessageMapper { public abstract class AbstractMessageMapper extends TransactionalMapper implements MessageMapper {
private static final Function<MailboxMessage, MessageUid> TO_UID = new Function<MailboxMessage, MessageUid>() {
@Override
public MessageUid apply(MailboxMessage input) {
return input.getUid();
}
};

private static final int UNLIMITED = -1;

protected final MailboxSession mailboxSession; protected final MailboxSession mailboxSession;
private final UidProvider uidProvider; private final UidProvider uidProvider;
private final ModSeqProvider modSeqProvider; private final ModSeqProvider modSeqProvider;
Expand Down Expand Up @@ -145,5 +156,9 @@ public MessageMetaData copy(Mailbox mailbox, MailboxMessage original) throws Mai
* Copy the MailboxMessage to the Mailbox, using the given uid and modSeq for the new MailboxMessage * Copy the MailboxMessage to the Mailbox, using the given uid and modSeq for the new MailboxMessage
*/ */
protected abstract MessageMetaData copy(Mailbox mailbox, MessageUid uid, long modSeq, MailboxMessage original) throws MailboxException; protected abstract MessageMetaData copy(Mailbox mailbox, MessageUid uid, long modSeq, MailboxMessage original) throws MailboxException;


@Override
public Iterator<MessageUid> listAllMessageUids(Mailbox mailbox) throws MailboxException {
return Iterators.transform(findInMailbox(mailbox, MessageRange.all(), FetchType.Metadata, UNLIMITED), TO_UID);
}
} }
Expand Up @@ -172,6 +172,11 @@ Iterator<UpdatedFlags> updateFlags(Mailbox mailbox, FlagsUpdateCalculator flagsU


Flags getApplicableFlag(Mailbox mailbox) throws MailboxException; Flags getApplicableFlag(Mailbox mailbox) throws MailboxException;


/**
* Return a list containing all MessageUid of Messages that belongs to given {@link Mailbox}
*/
Iterator<MessageUid> listAllMessageUids(Mailbox mailbox) throws MailboxException;

/** /**
* Specify what data needs to get filled in a {@link MailboxMessage} before returning it * Specify what data needs to get filled in a {@link MailboxMessage} before returning it
* *
Expand Down
Expand Up @@ -377,8 +377,7 @@ public void appendMessageFromMessageManagerAndSetInMailboxFromMessageIdManagerSh
messageIdManager.setInMailboxes(messageId, ImmutableList.of(mailbox1.getMailboxId(), mailbox2.getMailboxId()), session); messageIdManager.setInMailboxes(messageId, ImmutableList.of(mailbox1.getMailboxId(), mailbox2.getMailboxId()), session);


Flags expected = ApplicableFlagBuilder Flags expected = ApplicableFlagBuilder
.builder() .from(messageFlag)
.add(messageFlag)
.build(); .build();


assertThat(messageManager1.getApplicableFlags(session)) assertThat(messageManager1.getApplicableFlags(session))
Expand All @@ -405,8 +404,8 @@ public void appendMessageFromMessageManagerAndSetFlagsFromMessageIdManagerShould
messageIdManager.setFlags(deleted, FlagsUpdateMode.ADD, messageId, ImmutableList.of(mailbox1.getMailboxId()), session); messageIdManager.setFlags(deleted, FlagsUpdateMode.ADD, messageId, ImmutableList.of(mailbox1.getMailboxId()), session);


assertThat(messageManager1.getApplicableFlags(session)) assertThat(messageManager1.getApplicableFlags(session))
.isEqualTo(ApplicableFlagBuilder.builder() .isEqualTo(ApplicableFlagBuilder
.add(USER_FLAGS_VALUE, ANOTHER_USER_FLAGS_VALUE) .from(USER_FLAGS_VALUE, ANOTHER_USER_FLAGS_VALUE)
.build()); .build());
} }


Expand All @@ -422,9 +421,8 @@ public void setFlagsFromMessageManagerAndSetFlagsFromMessageIdManagerShouldUpdat
Flags applicableFlags = messageManager1.getApplicableFlags(session); Flags applicableFlags = messageManager1.getApplicableFlags(session);


assertThat(applicableFlags) assertThat(applicableFlags)
.isEqualTo(ApplicableFlagBuilder.builder() .isEqualTo(ApplicableFlagBuilder
.add(customFlag1) .from(customFlag1, customFlag2)
.add(customFlag2)
.build()); .build());
} }


Expand All @@ -437,15 +435,44 @@ public void setInMailboxFromMessageIdManagerAndSetFlagsFromMessageManagerShouldU
messageIdManager.setInMailboxes(messageId, ImmutableList.of(mailbox1.getMailboxId(), mailbox2.getMailboxId()), session); messageIdManager.setInMailboxes(messageId, ImmutableList.of(mailbox1.getMailboxId(), mailbox2.getMailboxId()), session);
messageManager2.setFlags(custom2, FlagsUpdateMode.ADD, MessageRange.all(), session); messageManager2.setFlags(custom2, FlagsUpdateMode.ADD, MessageRange.all(), session);


Flags expected = ApplicableFlagBuilder.builder() Flags expected = ApplicableFlagBuilder
.add(custom1) .from(custom1, custom2)
.add(custom2)
.build(); .build();


assertThat(messageManager2.getApplicableFlags(session)) assertThat(messageManager2.getApplicableFlags(session))
.isEqualTo(expected); .isEqualTo(expected);
} }


@Test
public void getUidsShouldInteractWellWithSetInMailboxes() throws Exception {
MessageId messageId = messageManager1.appendMessage(new ByteArrayInputStream(MAIL_CONTENT), new Date(), session, false, new Flags())
.getMessageId();

messageIdManager.setInMailboxes(messageId, ImmutableList.of(mailbox1.getMailboxId(), mailbox2.getMailboxId()), session);

List<MessageResult> listMessages = messageIdManager.getMessages(ImmutableList.of(messageId), FetchGroupImpl.MINIMAL, session);
MessageUid uid2 = FluentIterable.from(listMessages)
.filter(messageInMailbox2())
.get(0)
.getUid();

SearchQuery searchQuery = new SearchQuery(SearchQuery.all());
assertThat(messageManager2.search(searchQuery, session))
.hasSize(1)
.containsOnly(uid2);
}

@Test
public void getUidsShouldInteractWellWithDelete() throws Exception {
MessageId messageId = messageManager1.appendMessage(new ByteArrayInputStream(MAIL_CONTENT), new Date(), session, false, new Flags())
.getMessageId();

messageIdManager.delete(messageId, ImmutableList.of(mailbox1.getMailboxId()), session);

SearchQuery searchQuery = new SearchQuery(SearchQuery.all());
assertThat(messageManager1.search(searchQuery, session)).isEmpty();
}

private Predicate<MessageResult> messageInMailbox2() { private Predicate<MessageResult> messageInMailbox2() {
return new Predicate<MessageResult>() { return new Predicate<MessageResult>() {
@Override @Override
Expand Down
Expand Up @@ -76,7 +76,12 @@ private final class TestMessageMapper implements MessageMapper {
public TestMessageMapper(MessageRange messageRange) { public TestMessageMapper(MessageRange messageRange) {
this.messageRange = messageRange; this.messageRange = messageRange;
} }


@Override
public Iterator<MessageUid> listAllMessageUids(Mailbox mailbox) throws MailboxException {
return messageRange.iterator();
}

@Override @Override
public void endRequest() { public void endRequest() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
Expand Down

0 comments on commit e6f33c3

Please sign in to comment.