JAMES-1894 Push GetMessageList sorting and limit to the back-end
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/299addd9 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/299addd9 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/299addd9 Branch: refs/heads/master Commit: 299addd9415e3744702c44c61bebe3d15e0e5e77 Parents: 7a893c4 Author: Benoit Tellier <btell...@linagora.com> Authored: Thu Dec 22 18:40:05 2016 +0700 Committer: Benoit Tellier <btell...@linagora.com> Committed: Mon Jan 9 22:01:01 2017 +0700 ---------------------------------------------------------------------- .../apache/james/mailbox/MailboxManager.java | 7 +- ...lasticSearchListeningMessageSearchIndex.java | 18 +- .../search/ElasticSearchSearcher.java | 38 +-- .../ElasticSearchIntegrationTest.java | 5 +- .../lucene/search/LuceneMessageSearchIndex.java | 65 +++-- .../LuceneMailboxMessageSearchIndexTest.java | 68 +++-- .../search/LuceneMessageSearchIndexTest.java | 6 +- .../mailbox/store/StoreMailboxManager.java | 9 +- .../store/search/LazyMessageSearchIndex.java | 5 +- .../store/search/MessageSearchIndex.java | 31 ++- .../mailbox/store/search/MessageSearches.java | 25 +- .../store/search/SimpleMessageSearchIndex.java | 77 ++++-- .../james/mailbox/store/MessageBuilder.java | 7 +- .../search/AbstractMessageSearchIndexTest.java | 255 ++++++++++--------- .../host/ElasticSearchHostSystem.java | 7 +- .../host/LuceneSearchHostSystem.java | 2 +- .../base/MailboxEventAnalyserTest.java | 2 +- .../jmap/methods/GetMessageListMethod.java | 83 +----- .../jmap/utils/SortToComparatorConvertor.java | 85 ------- .../FirstUserConnectionFilterThreadTest.java | 6 +- .../utils/SortToComparatorConvertorTest.java | 146 ----------- 21 files changed, 396 insertions(+), 551 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java index 44d1df5..d152466 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java @@ -19,10 +19,8 @@ package org.apache.james.mailbox; -import java.util.Collection; import java.util.EnumSet; import java.util.List; -import java.util.Map; import java.util.Set; import org.apache.james.mailbox.exception.AnnotationException; @@ -33,11 +31,12 @@ import org.apache.james.mailbox.exception.MailboxNotFoundException; import org.apache.james.mailbox.exception.UnsupportedRightException; import org.apache.james.mailbox.model.MailboxACL; import org.apache.james.mailbox.model.MailboxAnnotation; -import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.model.MailboxAnnotationKey; +import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.model.MailboxMetaData; import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.mailbox.model.MailboxQuery; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MessageRange; import org.apache.james.mailbox.model.MultimailboxesSearchQuery; import org.apache.james.mailbox.model.SimpleMailboxACL; @@ -239,7 +238,7 @@ public interface MailboxManager extends RequestAware, MailboxListenerSupport { * the context for this call, not null * @throws MailboxException */ - Map<MailboxId, Collection<MessageUid>> search(MultimailboxesSearchQuery expression, MailboxSession session) throws MailboxException; + List<MessageId> search(MultimailboxesSearchQuery expression, MailboxSession session, long limit) throws MailboxException; /** * Does the given mailbox exist? http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndex.java ---------------------------------------------------------------------- diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndex.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndex.java index f4c60f8..281f429 100644 --- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndex.java +++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/events/ElasticSearchListeningMessageSearchIndex.java @@ -20,11 +20,10 @@ package org.apache.james.mailbox.elasticsearch.events; import static org.elasticsearch.index.query.QueryBuilders.termQuery; -import java.util.Collection; import java.util.EnumSet; import java.util.Iterator; import java.util.List; -import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import javax.inject.Inject; @@ -38,6 +37,7 @@ import org.apache.james.mailbox.elasticsearch.json.MessageToElasticSearchJson; import org.apache.james.mailbox.elasticsearch.search.ElasticSearchSearcher; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MultimailboxesSearchQuery; import org.apache.james.mailbox.model.SearchQuery; import org.apache.james.mailbox.model.UpdatedFlags; @@ -49,6 +49,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.JsonProcessingException; +import com.github.steveash.guavate.Guavate; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -85,17 +86,20 @@ public class ElasticSearchListeningMessageSearchIndex extends ListeningMessageSe Preconditions.checkArgument(session != null, "'session' is mandatory"); MailboxId mailboxId = mailbox.getMailboxId(); MultimailboxesSearchQuery query = MultimailboxesSearchQuery.from(searchQuery).inMailboxes(mailboxId).build(); + Optional<Long> noLimit = Optional.empty(); return searcher - .search(ImmutableList.of(session.getUser()), query) - .get(mailboxId) + .search(ImmutableList.of(session.getUser()), query, noLimit) + .map(SearchResult::getMessageUid) .iterator(); } @Override - public Map<MailboxId, Collection<MessageUid>> search(MailboxSession session, MultimailboxesSearchQuery searchQuery) + public List<MessageId> search(MailboxSession session, MultimailboxesSearchQuery searchQuery, long limit) throws MailboxException { Preconditions.checkArgument(session != null, "'session' is mandatory"); - return searcher.search(ImmutableList.of(session.getUser()), searchQuery).asMap(); + return searcher.search(ImmutableList.of(session.getUser()), searchQuery, Optional.of(limit)) + .map(SearchResult::getMessageId) + .collect(Guavate.toImmutableList()); } @Override @@ -156,5 +160,5 @@ public class ElasticSearchListeningMessageSearchIndex extends ListeningMessageSe private String indexIdFor(Mailbox mailbox, MessageUid uid) { return String.join(ID_SEPARATOR, mailbox.getMailboxId().serialize(), String.valueOf(uid.asLong())); } - + } http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcher.java ---------------------------------------------------------------------- diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcher.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcher.java index 1a5cd1e..e508e7d 100644 --- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcher.java +++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcher.java @@ -26,7 +26,6 @@ import java.util.stream.StreamSupport; import javax.inject.Inject; -import org.apache.commons.lang3.tuple.Pair; import org.apache.james.mailbox.MailboxSession.User; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.elasticsearch.ElasticSearchIndexer; @@ -36,7 +35,10 @@ import org.apache.james.mailbox.elasticsearch.query.SortConverter; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.model.MailboxId.Factory; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MultimailboxesSearchQuery; +import org.apache.james.mailbox.store.search.MessageSearchIndex; +import org.apache.james.mailbox.store.search.SimpleMessageSearchIndex; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.Client; @@ -46,9 +48,6 @@ import org.elasticsearch.search.SearchHitField; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.github.steveash.guavate.Guavate; -import com.google.common.collect.Multimap; - public class ElasticSearchSearcher { private static final Logger LOGGER = LoggerFactory.getLogger(ElasticSearchSearcher.class); @@ -59,23 +58,26 @@ public class ElasticSearchSearcher { private final QueryConverter queryConverter; private final int size; private final Factory mailboxIdFactory; + private final MessageId.Factory messageIdFactory; @Inject - public ElasticSearchSearcher(Client client, QueryConverter queryConverter, MailboxId.Factory mailboxIdFactory) { - this(client, queryConverter, DEFAULT_SIZE, mailboxIdFactory); + public ElasticSearchSearcher(Client client, QueryConverter queryConverter, MailboxId.Factory mailboxIdFactory, MessageId.Factory messageIdFactory) { + this(client, queryConverter, DEFAULT_SIZE, mailboxIdFactory, messageIdFactory); } - public ElasticSearchSearcher(Client client, QueryConverter queryConverter, int size, MailboxId.Factory mailboxIdFactory) { + public ElasticSearchSearcher(Client client, QueryConverter queryConverter, int size, Factory mailboxIdFactory, MessageId.Factory messageIdFactory) { this.client = client; this.queryConverter = queryConverter; this.size = size; this.mailboxIdFactory = mailboxIdFactory; + this.messageIdFactory = messageIdFactory; } - public Multimap<MailboxId, MessageUid> search(List<User> users, MultimailboxesSearchQuery query) throws MailboxException { - return new ScrollIterable(client, getSearchRequestBuilder(client, users, query)).stream() - .flatMap(this::transformResponseToUidStream) - .collect(Guavate.toImmutableListMultimap(Pair::getLeft, Pair::getRight)); + public Stream<MessageSearchIndex.SearchResult> search(List<User> users, MultimailboxesSearchQuery query, Optional<Long> limit) throws MailboxException { + Stream<MessageSearchIndex.SearchResult> pairStream = new ScrollIterable(client, getSearchRequestBuilder(client, users, query)).stream() + .flatMap(this::transformResponseToUidStream); + return limit.map(pairStream::limit) + .orElse(pairStream); } private SearchRequestBuilder getSearchRequestBuilder(Client client, List<User> users, MultimailboxesSearchQuery query) { @@ -92,21 +94,25 @@ public class ElasticSearchSearcher { (partialResult1, partialResult2) -> partialResult1); } - private Stream<Pair<MailboxId, MessageUid>> transformResponseToUidStream(SearchResponse searchResponse) { + private Stream<MessageSearchIndex.SearchResult> transformResponseToUidStream(SearchResponse searchResponse) { return StreamSupport.stream(searchResponse.getHits().spliterator(), false) .map(this::extractContentFromHit) .filter(Optional::isPresent) .map(Optional::get); } - private Optional<Pair<MailboxId, MessageUid>> extractContentFromHit(SearchHit hit) { + private Optional<MessageSearchIndex.SearchResult> extractContentFromHit(SearchHit hit) { SearchHitField mailboxId = hit.field(JsonMessageConstants.MAILBOX_ID); SearchHitField uid = hit.field(JsonMessageConstants.UID); - if (mailboxId != null && uid != null) { + SearchHitField id = hit.field(JsonMessageConstants.ID); + if (mailboxId != null && uid != null && id != null) { Number uidAsNumber = uid.getValue(); - return Optional.of(Pair.of(mailboxIdFactory.fromString(mailboxId.getValue()), MessageUid.of(uidAsNumber.longValue()))); + return Optional.of( + new MessageSearchIndex.SearchResult(messageIdFactory.fromString(id.getValue()), + mailboxIdFactory.fromString(mailboxId.getValue()), + MessageUid.of(uidAsNumber.longValue()))); } else { - LOGGER.warn("Can not extract UID and/or MailboxId for search result " + hit.getId()); + LOGGER.warn("Can not extract UID, MessageID and/or MailboxId for search result " + hit.getId()); return Optional.empty(); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java ---------------------------------------------------------------------- diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java index e633bb4..749f11b 100644 --- a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java +++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java @@ -67,9 +67,10 @@ public class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest IndexCreationFactory.createIndex(new TestingClientProvider(embeddedElasticSearch.getNode()).get()) ); MailboxSessionMapperFactory mapperFactory = new InMemoryMailboxSessionMapperFactory(); + InMemoryMessageId.Factory messageIdFactory = new InMemoryMessageId.Factory(); messageSearchIndex = new ElasticSearchListeningMessageSearchIndex(mapperFactory, new ElasticSearchIndexer(client, new DeleteByQueryPerformer(client, Executors.newSingleThreadExecutor(), BATCH_SIZE)), - new ElasticSearchSearcher(client, new QueryConverter(new CriterionConverter()), SEARCH_SIZE, new InMemoryId.Factory()), + new ElasticSearchSearcher(client, new QueryConverter(new CriterionConverter()), SEARCH_SIZE, new InMemoryId.Factory(), messageIdFactory), new MessageToElasticSearchJson(new DefaultTextExtractor(), ZoneId.of("Europe/Paris"), IndexAttachments.YES)); storeMailboxManager = new InMemoryMailboxManager( mapperFactory, @@ -78,7 +79,7 @@ public class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest new UnionMailboxACLResolver(), new SimpleGroupMembershipResolver(), new MessageParser(), - new InMemoryMessageId.Factory()); + messageIdFactory); storeMailboxManager.setMessageSearchIndex(messageSearchIndex); storeMailboxManager.init(); } http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java ---------------------------------------------------------------------- diff --git a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java index 8a683d9..7dee3cf 100644 --- a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java +++ b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java @@ -33,7 +33,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.Set; import java.util.TimeZone; @@ -48,6 +47,7 @@ import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.exception.UnsupportedSearchException; import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.model.MailboxId.Factory; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MessageRange; import org.apache.james.mailbox.model.MultimailboxesSearchQuery; import org.apache.james.mailbox.model.SearchQuery; @@ -117,10 +117,11 @@ import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.Version; +import com.google.common.base.Function; import com.google.common.base.Preconditions; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Multimap; /** * Lucene based {@link ListeningMessageSearchIndex} which offers message searching via a Lucene index @@ -264,6 +265,11 @@ public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex { public final static String MAILBOX_ID_FIELD ="mailboxid"; /** + * {@link Field} which will contain the id of the {@link MessageId} + */ + public final static String MESSAGE_ID_FIELD ="messageid"; + + /** * {@link Field} which contain the Date header of the message with YEAR-Resolution */ public final static String SENT_DATE_FIELD_YEAR_RESOLUTION ="sentdateYearResolution"; @@ -341,6 +347,7 @@ public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex { private final static SortField FIRST_FROM_MAILBOX_DISPLAY_SORT_REVERSE = new SortField(FIRST_FROM_MAILBOX_DISPLAY_FIELD, SortField.STRING, true); private final Factory mailboxIdFactory; + private final MessageId.Factory messageIdFactory; private final IndexWriter writer; private int maxQueryResults = DEFAULT_MAX_QUERY_RESULTS; @@ -348,21 +355,23 @@ public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex { private boolean suffixMatch = false; @Inject - public LuceneMessageSearchIndex(MessageMapperFactory factory, MailboxId.Factory mailboxIdFactory, Directory directory) throws CorruptIndexException, LockObtainFailedException, IOException { - this(factory, mailboxIdFactory, directory, false, true); + public LuceneMessageSearchIndex(MessageMapperFactory factory, Factory mailboxIdFactory, Directory directory, MessageId.Factory messageIdFactory) throws CorruptIndexException, LockObtainFailedException, IOException { + this(factory, mailboxIdFactory, directory, false, true, messageIdFactory); } - public LuceneMessageSearchIndex(MessageMapperFactory factory, MailboxId.Factory mailboxIdFactory, Directory directory, boolean dropIndexOnStart, boolean lenient) throws CorruptIndexException, LockObtainFailedException, IOException { + public LuceneMessageSearchIndex(MessageMapperFactory factory, Factory mailboxIdFactory, Directory directory, boolean dropIndexOnStart, boolean lenient, MessageId.Factory messageIdFactory) throws CorruptIndexException, LockObtainFailedException, IOException { super(factory); this.mailboxIdFactory = mailboxIdFactory; + this.messageIdFactory = messageIdFactory; this.writer = new IndexWriter(directory, createConfig(createAnalyzer(lenient), dropIndexOnStart)); } - public LuceneMessageSearchIndex(MessageMapperFactory factory, MailboxId.Factory mailboxIdFactory, IndexWriter writer) { + public LuceneMessageSearchIndex(MessageMapperFactory factory, Factory mailboxIdFactory, MessageId.Factory messageIdFactory, IndexWriter writer) { super(factory); this.mailboxIdFactory = mailboxIdFactory; + this.messageIdFactory = messageIdFactory; this.writer = writer; } @@ -431,24 +440,36 @@ public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex { public Iterator<MessageUid> search(MailboxSession session, Mailbox mailbox, SearchQuery searchQuery) throws MailboxException { Preconditions.checkArgument(session != null, "'session' is mandatory"); MailboxId mailboxId = mailbox.getMailboxId(); - Multimap<MailboxId, MessageUid> results = - searchMultimap( - session, - MultimailboxesSearchQuery - .from(searchQuery) - .inMailboxes(mailboxId) - .build()); - return results.get(mailboxId).iterator(); + return FluentIterable.from(searchMultimap( + MultimailboxesSearchQuery + .from(searchQuery) + .inMailboxes(mailboxId) + .build())) + .transform(new Function<SearchResult, MessageUid>() { + @Override + public MessageUid apply(SearchResult input) { + return input.getMessageUid(); + } + }) + .iterator(); } @Override - public Map<MailboxId, Collection<MessageUid>> search(MailboxSession session, MultimailboxesSearchQuery searchQuery) throws MailboxException { + public List<MessageId> search(MailboxSession session, MultimailboxesSearchQuery searchQuery, long limit) throws MailboxException { Preconditions.checkArgument(session != null, "'session' is mandatory"); - return searchMultimap(session, searchQuery).asMap(); + return FluentIterable.from(searchMultimap(searchQuery)) + .transform(new Function<SearchResult, MessageId>() { + @Override + public MessageId apply(SearchResult input) { + return input.getMessageId(); + } + }) + .limit(Long.valueOf(limit).intValue()) + .toList(); } - private Multimap<MailboxId, MessageUid> searchMultimap(MailboxSession session, MultimailboxesSearchQuery searchQuery) throws MailboxException { - Multimap<MailboxId, MessageUid> results = LinkedHashMultimap.create(); + private List<SearchResult> searchMultimap(MultimailboxesSearchQuery searchQuery) throws MailboxException { + ImmutableList.Builder<SearchResult> results = ImmutableList.builder(); IndexSearcher searcher = null; Query inMailboxes = buildQueryFromMailboxes(searchQuery.getInMailboxes()); @@ -471,7 +492,8 @@ public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex { Document doc = searcher.doc(sDoc.doc); MessageUid uid = MessageUid.of(Long.valueOf(doc.get(UID_FIELD))); MailboxId mailboxId = mailboxIdFactory.fromString(doc.get(MAILBOX_ID_FIELD)); - results.put(mailboxId, uid); + MessageId messageId = messageIdFactory.fromString(doc.get(MESSAGE_ID_FIELD)); + results.add(new SearchResult(messageId, mailboxId, uid)); } } catch (IOException e) { throw new MailboxException("Unable to search the mailbox", e); @@ -484,7 +506,7 @@ public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex { } } } - return results; + return results.build(); } private Query buildQueryFromMailboxes(ImmutableSet<MailboxId> mailboxIds) { @@ -513,6 +535,7 @@ public class LuceneMessageSearchIndex extends ListeningMessageSearchIndex { // TODO: Better handling doc.add(new Field(MAILBOX_ID_FIELD, membership.getMailboxId().serialize().toUpperCase(Locale.ENGLISH), Store.YES, Index.NOT_ANALYZED)); doc.add(new NumericField(UID_FIELD,Store.YES, true).setLongValue(membership.getUid().asLong())); + doc.add(new Field(MESSAGE_ID_FIELD, membership.getMessageId().serialize(), Store.YES, Index.NOT_ANALYZED)); // create an unqiue key for the document which can be used later on updates to find the document doc.add(new Field(ID_FIELD, membership.getMailboxId().serialize().toUpperCase(Locale.ENGLISH) +"-" + Long.toString(membership.getUid().asLong()), Store.YES, Index.NOT_ANALYZED)); http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java ---------------------------------------------------------------------- diff --git a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java index 6bf144c..82d8cba 100644 --- a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java +++ b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java @@ -23,10 +23,10 @@ import static org.assertj.core.api.Assertions.assertThat; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Calendar; -import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Locale; import java.util.Map; @@ -38,6 +38,7 @@ import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.mock.MockMailboxSession; import org.apache.james.mailbox.model.MailboxACL; import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MultimailboxesSearchQuery; import org.apache.james.mailbox.model.SearchQuery; import org.apache.james.mailbox.model.SearchQuery.AddressType; @@ -45,9 +46,9 @@ import org.apache.james.mailbox.model.SearchQuery.DateResolution; import org.apache.james.mailbox.model.SearchQuery.Sort.SortClause; import org.apache.james.mailbox.model.SimpleMailboxACL; import org.apache.james.mailbox.model.TestId; +import org.apache.james.mailbox.model.TestMessageId; import org.apache.james.mailbox.store.MessageBuilder; import org.apache.james.mailbox.store.SimpleMailboxMembership; -import org.apache.james.mailbox.store.mail.model.DefaultMessageId; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.lucene.store.RAMDirectory; import org.junit.Before; @@ -55,7 +56,8 @@ import org.junit.Test; public class LuceneMailboxMessageSearchIndexTest { - private LuceneMessageSearchIndex index; + public static final long LIMIT = 100L; + private LuceneMessageSearchIndex index; private SimpleMailbox mailbox = new SimpleMailbox(0); private SimpleMailbox mailbox2 = new SimpleMailbox(1); @@ -79,6 +81,11 @@ public class LuceneMailboxMessageSearchIndexTest { private MessageUid uid3; private MessageUid uid4; private MessageUid uid5; + private MessageId id1; + private MessageId id2; + private MessageId id3; + private MessageId id4; + private MessageId id5; protected boolean useLenient() { return true; @@ -86,7 +93,13 @@ public class LuceneMailboxMessageSearchIndexTest { @Before public void setUp() throws Exception { - index = new LuceneMessageSearchIndex(null, new TestId.Factory(), new RAMDirectory(), true, useLenient()); + TestMessageId.Factory factory = new TestMessageId.Factory(); + id1 = factory.generate(); + id2 = factory.generate(); + id3 = factory.generate(); + id4 = factory.generate(); + id5 = factory.generate(); + index = new LuceneMessageSearchIndex(null, new TestId.Factory(), new RAMDirectory(), true, useLenient(), factory); index.setEnableSuffixMatch(true); Map<String, String> headersSubject = new HashMap<String, String>(); headersSubject.put("Subject", "test (fwd)"); @@ -107,23 +120,23 @@ public class LuceneMailboxMessageSearchIndexTest { headersTestSubject.put("Cc", "test211 <test21@localhost>, test6 <test6@foobar>"); uid1 = MessageUid.of(1); - SimpleMailboxMembership m = new SimpleMailboxMembership(new DefaultMessageId(), mailbox.getMailboxId(), uid1, 0, new Date(), 200, new Flags(Flag.ANSWERED), "My Body".getBytes(), headersSubject); + SimpleMailboxMembership m = new SimpleMailboxMembership(id1, mailbox.getMailboxId(), uid1, 0, new Date(), 200, new Flags(Flag.ANSWERED), "My Body".getBytes(), headersSubject); index.add(null, mailbox, m); uid2 = MessageUid.of(1); - SimpleMailboxMembership m2 = new SimpleMailboxMembership(new DefaultMessageId(), mailbox2.getMailboxId(), uid2, 0, new Date(), 20, new Flags(Flag.ANSWERED), "My Body".getBytes(), headersSubject); + SimpleMailboxMembership m2 = new SimpleMailboxMembership(id2, mailbox2.getMailboxId(), uid2, 0, new Date(), 20, new Flags(Flag.ANSWERED), "My Body".getBytes(), headersSubject); index.add(null, mailbox2, m2); uid3 = MessageUid.of(2); Calendar cal = Calendar.getInstance(); cal.set(1980, 2, 10); - SimpleMailboxMembership m3 = new SimpleMailboxMembership(new DefaultMessageId(), mailbox.getMailboxId(), uid3, 0, cal.getTime(), 20, new Flags(Flag.DELETED), "My Otherbody".getBytes(), headersTest); + SimpleMailboxMembership m3 = new SimpleMailboxMembership(id3, mailbox.getMailboxId(), uid3, 0, cal.getTime(), 20, new Flags(Flag.DELETED), "My Otherbody".getBytes(), headersTest); index.add(null, mailbox, m3); uid4 = MessageUid.of(3); Calendar cal2 = Calendar.getInstance(); cal2.set(8000, 2, 10); - SimpleMailboxMembership m4 = new SimpleMailboxMembership(new DefaultMessageId(), mailbox.getMailboxId(), uid4, 0, cal2.getTime(), 20, new Flags(Flag.DELETED), "My Otherbody2".getBytes(), headersTestSubject); + SimpleMailboxMembership m4 = new SimpleMailboxMembership(id4, mailbox.getMailboxId(), uid4, 0, cal2.getTime(), 20, new Flags(Flag.DELETED), "My Otherbody2".getBytes(), headersTestSubject); index.add(null, mailbox, m4); uid5 = MessageUid.of(10); @@ -136,7 +149,7 @@ public class LuceneMailboxMessageSearchIndexTest { builder.uid = uid5; builder.mailboxId = mailbox3.getMailboxId(); - index.add(null, mailbox3, builder.build()); + index.add(null, mailbox3, builder.build(id5)); session = new MockMailboxSession("username"); } @@ -267,29 +280,44 @@ public class LuceneMailboxMessageSearchIndexTest { public void searchBodyInAllMailboxesShouldMatch() throws Exception { SearchQuery query = new SearchQuery(); query.andCriteria(SearchQuery.bodyContains("My Body")); - Map<MailboxId, Collection<MessageUid>> result = index.search(session, MultimailboxesSearchQuery.from(query).build()); - assertThat(result).hasSize(2); - assertThat(result.get(mailbox.id)).containsExactly(uid1); - assertThat(result.get(mailbox2.id)).containsExactly(uid2); + + List<MessageId> result = index.search(session, MultimailboxesSearchQuery.from(query).build(), LIMIT); + + assertThat(result).containsOnly(id1, id2); } @Test public void searchBodyInSpecificMailboxesShouldMatch() throws Exception { SearchQuery query = new SearchQuery(); query.andCriteria(SearchQuery.bodyContains("My Body")); - Map<MailboxId, Collection<MessageUid>> result = index.search(session, - MultimailboxesSearchQuery.from(query).inMailboxes(mailbox.id, mailbox3.id).build()); - assertThat(result).hasSize(1); - assertThat(result.get(mailbox.id)).containsExactly(uid1); - } + List<MessageId> result = index.search(session, + MultimailboxesSearchQuery.from(query).inMailboxes(mailbox.id, mailbox3.id).build(), + LIMIT); + + assertThat(result).containsOnly(id1); + } @Test public void searchAllShouldMatchAllUserEmails() throws Exception { SearchQuery query = new SearchQuery(); query.andCriteria(SearchQuery.all()); - Map<MailboxId, Collection<MessageUid>> result = index.search(session, MultimailboxesSearchQuery.from(query).build()); - assertThat(result).hasSize(3); + + List<MessageId> result = index.search(session, MultimailboxesSearchQuery.from(query).build(), LIMIT); + + // The query is not limited to one mailbox and we have 5 indexed messages + assertThat(result).hasSize(5); + } + + @Test + public void searchAllShouldLimitTheSize() throws Exception { + SearchQuery query = new SearchQuery(); + query.andCriteria(SearchQuery.all()); + + int limit = 1; + List<MessageId> result = index.search(session, MultimailboxesSearchQuery.from(query).build(), limit); + + assertThat(result).hasSize(limit); } @Test http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java ---------------------------------------------------------------------- diff --git a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java index 0270e40..864a7a0 100644 --- a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java +++ b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java @@ -26,6 +26,7 @@ import org.apache.james.mailbox.inmemory.InMemoryId; import org.apache.james.mailbox.inmemory.InMemoryMailboxManager; import org.apache.james.mailbox.inmemory.InMemoryMailboxSessionMapperFactory; import org.apache.james.mailbox.inmemory.InMemoryMessageId; +import org.apache.james.mailbox.model.TestMessageId; import org.apache.james.mailbox.store.FakeAuthenticator; import org.apache.james.mailbox.store.JVMMailboxPathLocker; import org.apache.james.mailbox.store.MailboxSessionMapperFactory; @@ -42,8 +43,9 @@ public class LuceneMessageSearchIndexTest extends AbstractMessageSearchIndexTest @Override protected void initializeMailboxManager() throws Exception { + TestMessageId.Factory messageIdFactory = new TestMessageId.Factory(); MailboxSessionMapperFactory mapperFactory = new InMemoryMailboxSessionMapperFactory(); - messageSearchIndex = new LuceneMessageSearchIndex(mapperFactory, new InMemoryId.Factory(), new RAMDirectory()); + messageSearchIndex = new LuceneMessageSearchIndex(mapperFactory, new InMemoryId.Factory(), new RAMDirectory(), messageIdFactory); storeMailboxManager = new InMemoryMailboxManager( mapperFactory, new FakeAuthenticator(), @@ -51,7 +53,7 @@ public class LuceneMessageSearchIndexTest extends AbstractMessageSearchIndexTest new UnionMailboxACLResolver(), new SimpleGroupMembershipResolver(), new MessageParser(), - new InMemoryMessageId.Factory()); + messageIdFactory); storeMailboxManager.setMessageSearchIndex(messageSearchIndex); storeMailboxManager.init(); } http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java index 8bee086..5f83734 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java @@ -20,12 +20,10 @@ package org.apache.james.mailbox.store; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.Random; import java.util.Set; @@ -40,7 +38,6 @@ import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MailboxSession.SessionType; import org.apache.james.mailbox.MailboxSessionIdGenerator; import org.apache.james.mailbox.MessageManager; -import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.RequestAware; import org.apache.james.mailbox.StandardMailboxMetaDataComparator; import org.apache.james.mailbox.acl.GroupMembershipResolver; @@ -85,6 +82,8 @@ import org.apache.james.mailbox.store.transaction.Mapper; import org.apache.james.mailbox.store.transaction.TransactionalMapper; import org.slf4j.Logger; +import com.google.common.base.Optional; + /** * This base class of an {@link MailboxManager} implementation provides a high-level api for writing your own * {@link MailboxManager} implementation. If you plan to write your own {@link MailboxManager} its most times so easiest @@ -699,8 +698,8 @@ public class StoreMailboxManager implements MailboxManager { } @Override - public Map<MailboxId, Collection<MessageUid>> search(MultimailboxesSearchQuery expression, MailboxSession session) throws MailboxException { - return index.search(session, expression); + public List<MessageId> search(MultimailboxesSearchQuery expression, MailboxSession session, long limit) throws MailboxException { + return index.search(session, expression, limit); } public boolean belongsToNamespaceAndUser(MailboxPath base, Mailbox mailbox) { http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/LazyMessageSearchIndex.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/LazyMessageSearchIndex.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/LazyMessageSearchIndex.java index a1c9275..07c6188 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/LazyMessageSearchIndex.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/LazyMessageSearchIndex.java @@ -18,11 +18,9 @@ ****************************************************************/ package org.apache.james.mailbox.store.search; -import java.util.Collection; import java.util.EnumSet; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.james.mailbox.MailboxManager.SearchCapabilities; @@ -31,6 +29,7 @@ import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.exception.UnsupportedSearchException; import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MessageRange; import org.apache.james.mailbox.model.MultimailboxesSearchQuery; import org.apache.james.mailbox.model.SearchQuery; @@ -128,7 +127,7 @@ public class LazyMessageSearchIndex extends ListeningMessageSearchIndex { @Override - public Map<MailboxId, Collection<MessageUid>> search(MailboxSession session, MultimailboxesSearchQuery searchQuery) throws MailboxException { + public List<MessageId> search(MailboxSession session, MultimailboxesSearchQuery searchQuery, long limit) throws MailboxException { throw new UnsupportedSearchException(); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearchIndex.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearchIndex.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearchIndex.java index 6324898..3df16bd 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearchIndex.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearchIndex.java @@ -19,21 +19,20 @@ package org.apache.james.mailbox.store.search; -import java.util.Collection; import java.util.EnumSet; import java.util.Iterator; -import java.util.Map; +import java.util.List; import org.apache.james.mailbox.MailboxManager; import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MultimailboxesSearchQuery; import org.apache.james.mailbox.model.SearchQuery; import org.apache.james.mailbox.store.mail.model.Mailbox; - /** * An index which can be used to search for MailboxMessage UID's that match a {@link SearchQuery}. * @@ -50,8 +49,32 @@ public interface MessageSearchIndex { /** * Return all uids of all {@link Mailbox}'s the current user has access to which match the {@link SearchQuery} */ - Map<MailboxId, Collection<MessageUid>> search(MailboxSession session, MultimailboxesSearchQuery searchQuery) throws MailboxException; + List<MessageId> search(MailboxSession session, MultimailboxesSearchQuery searchQuery, long limit) throws MailboxException; EnumSet<MailboxManager.SearchCapabilities> getSupportedCapabilities(); + class SearchResult { + private final MessageId messageId; + private final MailboxId mailboxId; + private final MessageUid messageUid; + + public SearchResult(MessageId messageId, MailboxId mailboxId, MessageUid messageUid) { + this.messageId = messageId; + this.mailboxId = mailboxId; + this.messageUid = messageUid; + } + + public MessageId getMessageId() { + return messageId; + } + + public MailboxId getMailboxId() { + return mailboxId; + } + + public MessageUid getMessageUid() { + return messageUid; + } + } + } http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java index f90c144..c2126f1 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/MessageSearches.java @@ -29,7 +29,6 @@ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collection; import java.util.Date; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -70,12 +69,14 @@ import org.apache.james.mime4j.message.DefaultMessageWriter; import org.apache.james.mime4j.message.HeaderImpl; import org.apache.james.mime4j.utils.search.MessageMatcher; +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; import com.google.common.collect.Lists; /** * Utility methods to help perform search operations. */ -public class MessageSearches implements Iterable<MessageUid> { +public class MessageSearches implements Iterable<SimpleMessageSearchIndex.SearchResult> { private Iterator<MailboxMessage> messages; private SearchQuery query; @@ -93,7 +94,7 @@ public class MessageSearches implements Iterable<MessageUid> { public MessageSearches() { } - private Set<MessageUid> search() { + private Set<SimpleMessageSearchIndex.SearchResult> search() { TreeSet<MailboxMessage> matched = new TreeSet<MailboxMessage>(CombinedComparator.create(query.getSorts())); while (messages.hasNext()) { MailboxMessage m = messages.next(); @@ -107,12 +108,16 @@ public class MessageSearches implements Iterable<MessageUid> { } } } - Set<MessageUid> uids = new HashSet<MessageUid>(); - Iterator<MailboxMessage> matchedIt = matched.iterator(); - while (matchedIt.hasNext()) { - uids.add(matchedIt.next().getUid()); - } - return uids; + return FluentIterable.from(matched) + .transform(new Function<MailboxMessage, SimpleMessageSearchIndex.SearchResult>() { + @Override + public SimpleMessageSearchIndex.SearchResult apply(MailboxMessage input) { + return new SimpleMessageSearchIndex.SearchResult( + input.getMessageId(), + input.getMailboxId(), + input.getUid()); + } + }).toSet(); } /** @@ -631,7 +636,7 @@ public class MessageSearches implements Iterable<MessageUid> { * according to the SearchQuery * */ - public Iterator<MessageUid> iterator() { + public Iterator<SimpleMessageSearchIndex.SearchResult> iterator() { return search().iterator(); } http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/SimpleMessageSearchIndex.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/SimpleMessageSearchIndex.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/SimpleMessageSearchIndex.java index 18ea774..537164e 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/SimpleMessageSearchIndex.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/search/SimpleMessageSearchIndex.java @@ -19,11 +19,9 @@ package org.apache.james.mailbox.store.search; import java.util.ArrayList; -import java.util.Collection; import java.util.EnumSet; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; @@ -33,8 +31,8 @@ import org.apache.james.mailbox.MailboxManager.SearchCapabilities; import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.exception.MailboxException; -import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MessageRange; import org.apache.james.mailbox.model.MultimailboxesSearchQuery; import org.apache.james.mailbox.model.SearchQuery; @@ -49,13 +47,11 @@ import org.apache.james.mailbox.store.mail.MessageMapperFactory; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.ImmutableMultimap.Builder; -import com.google.common.collect.Multimap; /** * {@link MessageSearchIndex} which just fetch {@link MailboxMessage}'s from the {@link MessageMapper} and use {@link MessageSearcher} @@ -102,25 +98,26 @@ public class SimpleMessageSearchIndex implements MessageSearchIndex { } @Override - public Iterator<MessageUid> search(MailboxSession session, Mailbox mailbox, SearchQuery query) throws MailboxException { + public Iterator<MessageUid> search(MailboxSession session, final Mailbox mailbox, SearchQuery query) throws MailboxException { Preconditions.checkArgument(session != null, "'session' is mandatory"); - return searchMultimap(session, ImmutableList.of(mailbox), query) - .get(mailbox.getMailboxId()) + return FluentIterable.from(searchResults(session, ImmutableList.of(mailbox), query)) + .filter(isInMailbox(mailbox)) + .transform(toMessageUid()) .iterator(); } - - private Multimap<MailboxId, MessageUid> searchMultimap(MailboxSession session, Iterable<Mailbox> mailboxes, SearchQuery query) throws MailboxException { - Builder<MailboxId, MessageUid> multimap = ImmutableMultimap.builder(); + + private List<SearchResult> searchResults(MailboxSession session, Iterable<Mailbox> mailboxes, SearchQuery query) throws MailboxException { + ImmutableList.Builder<SearchResult> builder = ImmutableList.builder(); for (Mailbox mailbox: mailboxes) { - multimap.putAll(searchMultimap(session, mailbox, query)); + builder.addAll(searchResults(session, mailbox, query)); } - return multimap.build(); + return builder.build(); } - private Multimap<MailboxId, MessageUid> searchMultimap(MailboxSession session, Mailbox mailbox, SearchQuery query) throws MailboxException { + private List<SearchResult> searchResults(MailboxSession session, Mailbox mailbox, SearchQuery query) throws MailboxException { if (!isMatchingUser(session, mailbox)) { - return ImmutableMultimap.of(); + return ImmutableList.of(); } MessageMapper mapper = messageMapperFactory.getMessageMapper(session); @@ -145,11 +142,7 @@ public class SimpleMessageSearchIndex implements MessageSearchIndex { hitSet.add(m); } } - - // MessageSearches does the filtering for us - return ImmutableMultimap.<MailboxId, MessageUid>builder() - .putAll(mailbox.getMailboxId(), ImmutableList.copyOf(new MessageSearches(hitSet.iterator(), query, session).iterator())) - .build(); + return ImmutableList.copyOf(new MessageSearches(hitSet.iterator(), query, session).iterator()); } private boolean isMatchingUser(MailboxSession session, Mailbox mailbox) { @@ -157,7 +150,7 @@ public class SimpleMessageSearchIndex implements MessageSearchIndex { } @Override - public Map<MailboxId, Collection<MessageUid>> search(MailboxSession session, final MultimailboxesSearchQuery searchQuery) throws MailboxException { + public List<MessageId> search(MailboxSession session, final MultimailboxesSearchQuery searchQuery, long limit) throws MailboxException { List<Mailbox> allUserMailboxes = mailboxMapperFactory.getMailboxMapper(session) .findMailboxWithPathLike(new MailboxPath(session.getPersonalSpace(), session.getUser().getUserName(), WILDCARD)); FluentIterable<Mailbox> filteredMailboxes = FluentIterable.from(allUserMailboxes).filter(new Predicate<Mailbox>() { @@ -167,8 +160,7 @@ public class SimpleMessageSearchIndex implements MessageSearchIndex { } }); if (searchQuery.getInMailboxes().isEmpty()) { - return searchMultimap(session, filteredMailboxes, searchQuery.getSearchQuery()) - .asMap(); + return getAsMessageIds(searchResults(session, filteredMailboxes, searchQuery.getSearchQuery()), limit); } List<Mailbox> queriedMailboxes = new ArrayList<Mailbox>(); for (Mailbox mailbox: filteredMailboxes) { @@ -176,8 +168,41 @@ public class SimpleMessageSearchIndex implements MessageSearchIndex { queriedMailboxes.add(mailbox); } } - return searchMultimap(session, queriedMailboxes, searchQuery.getSearchQuery()) - .asMap(); + return getAsMessageIds(searchResults(session, queriedMailboxes, searchQuery.getSearchQuery()), limit); + } + + private List<MessageId> getAsMessageIds(List<SearchResult> temp, long limit) { + return FluentIterable.from(temp) + .transform(toMessageId()) + .limit(Long.valueOf(limit).intValue()) + .toList(); + } + + private Function<SearchResult, MessageId> toMessageId() { + return new Function<SearchResult, MessageId>() { + @Override + public MessageId apply(SearchResult input) { + return input.getMessageId(); + } + }; + } + + private Function<SearchResult, MessageUid> toMessageUid() { + return new Function<SearchResult, MessageUid>() { + @Override + public MessageUid apply(SearchResult input) { + return input.getMessageUid(); + } + }; + } + + private Predicate<SearchResult> isInMailbox(final Mailbox mailbox) { + return new Predicate<SearchResult>() { + @Override + public boolean apply(SearchResult input) { + return input.getMailboxId().equals(mailbox.getMailboxId()); + } + }; } } http://git-wip-us.apache.org/repos/asf/james-project/blob/299addd9/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageBuilder.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageBuilder.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageBuilder.java index c1cee99..59ec33b 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageBuilder.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageBuilder.java @@ -25,6 +25,7 @@ import java.util.Map; import javax.mail.Flags; import org.apache.james.mailbox.MessageUid; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.TestId; import org.apache.james.mailbox.store.mail.model.DefaultMessageId; import org.apache.james.mailbox.store.mail.model.MailboxMessage; @@ -41,7 +42,11 @@ public class MessageBuilder { public int lineNumber = 0; public MailboxMessage build() throws Exception { - return new SimpleMailboxMembership(new DefaultMessageId(), mailboxId, uid, -1, internalDate, size, flags, body, headers); + return build(new DefaultMessageId()); + } + + public MailboxMessage build(MessageId messageId) throws Exception { + return new SimpleMailboxMembership(messageId, mailboxId, uid, -1, internalDate, size, flags, body, headers); } public void header(String field, String value) { --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org