You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by rc...@apache.org on 2019/11/25 09:06:51 UTC
[james-project] 08/22: JAMES-2987 Add MessageMetadataViewFactory
This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 4cfab0f2b3db546c30911f749fcfedc4989dd269
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Nov 21 12:00:07 2019 +0700
JAMES-2987 Add MessageMetadataViewFactory
MessageViewFactory becomes the generic class converting MessageResults
into MessageView.
By avoiding the intermediate MessageContentWithMetadata, we can really
simplify new MessageView factories.
---
.../manager/InMemoryIntegrationResources.java | 12 +++
.../model/message/view/MessageFullViewFactory.java | 29 +-----
.../message/view/MessageMetadataViewFactory.java | 57 +++++++++++
.../model/message/view/MessageViewFactory.java | 67 +++++++++++++
.../view/MessageMetadataViewFactoryTest.java | 110 +++++++++++++++++++++
5 files changed, 251 insertions(+), 24 deletions(-)
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
index 29c4ae3..59e1a88 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
@@ -50,6 +50,8 @@ import org.apache.james.mailbox.store.FakeAuthorizator;
import org.apache.james.mailbox.store.JVMMailboxPathLocker;
import org.apache.james.mailbox.store.PreDeletionHooks;
import org.apache.james.mailbox.store.SessionProvider;
+import org.apache.james.mailbox.store.StoreAttachmentManager;
+import org.apache.james.mailbox.store.StoreBlobManager;
import org.apache.james.mailbox.store.StoreMailboxAnnotationManager;
import org.apache.james.mailbox.store.StoreMailboxManager;
import org.apache.james.mailbox.store.StoreMessageIdManager;
@@ -384,6 +386,7 @@ public class InMemoryIntegrationResources implements IntegrationResources<StoreM
private final StoreMessageIdManager storeMessageIdManager;
private final MessageSearchIndex searchIndex;
private final EventBus eventBus;
+ private final StoreBlobManager blobManager;
InMemoryIntegrationResources(InMemoryMailboxManager mailboxManager, StoreRightManager storeRightManager, MessageId.Factory messageIdFactory, InMemoryCurrentQuotaManager currentQuotaManager, DefaultUserQuotaRootResolver defaultUserQuotaRootResolver, InMemoryPerUserMaxQuotaManager maxQuotaManager, QuotaManager quotaManager, MessageSearchIndex searchIndex, EventBus eventBus) {
this.mailboxManager = mailboxManager;
@@ -404,6 +407,11 @@ public class InMemoryIntegrationResources implements IntegrationResources<StoreM
quotaManager,
defaultUserQuotaRootResolver,
mailboxManager.getPreDeletionHooks());
+
+ this.blobManager = new StoreBlobManager(
+ new StoreAttachmentManager((InMemoryMailboxSessionMapperFactory) mailboxManager.getMapperFactory(), storeMessageIdManager),
+ storeMessageIdManager,
+ messageIdFactory);
}
public DefaultUserQuotaRootResolver getDefaultUserQuotaRootResolver() {
@@ -450,4 +458,8 @@ public class InMemoryIntegrationResources implements IntegrationResources<StoreM
public EventBus getEventBus() {
return eventBus;
}
+
+ public StoreBlobManager getBlobManager() {
+ return blobManager;
+ }
}
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java
index 2f7d15b..ebef606 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java
@@ -40,7 +40,6 @@ import org.apache.james.jmap.draft.model.Emailer;
import org.apache.james.jmap.draft.model.Keywords;
import org.apache.james.jmap.draft.model.MessagePreviewGenerator;
import org.apache.james.jmap.draft.utils.HtmlTextExtractor;
-import org.apache.james.jmap.draft.utils.KeywordsCombiner;
import org.apache.james.mailbox.BlobManager;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.exception.MailboxException;
@@ -66,11 +65,9 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
-public class MessageFullViewFactory {
+public class MessageFullViewFactory implements MessageViewFactory<MessageFullView> {
public static final String JMAP_MULTIVALUED_FIELD_DELIMITER = "\n";
- private static final KeywordsCombiner ACCUMULATOR = new KeywordsCombiner();
-
private final BlobManager blobManager;
private final MessagePreviewGenerator messagePreview;
private final MessageContentExtractor messageContentExtractor;
@@ -87,6 +84,7 @@ public class MessageFullViewFactory {
this.keywordsFactory = Keywords.lenientFactory();
}
+ @Override
public MessageFullView fromMessageResults(Collection<MessageResult> messageResults) throws MailboxException {
return fromMetaDataWithContent(toMetaDataWithContent(messageResults));
}
@@ -122,20 +120,11 @@ public class MessageFullViewFactory {
}
private MetaDataWithContent toMetaDataWithContent(Collection<MessageResult> messageResults) throws MailboxException {
- Preconditions.checkArgument(!messageResults.isEmpty(), "MessageResults cannot be empty");
- Preconditions.checkArgument(hasOnlyOneMessageId(messageResults), "MessageResults need to share the same messageId");
+ assertOneMessageId(messageResults);
MessageResult firstMessageResult = messageResults.iterator().next();
- List<MailboxId> mailboxIds = messageResults.stream()
- .map(MessageResult::getMailboxId)
- .distinct()
- .collect(Guavate.toImmutableList());
-
- Keywords keywords = messageResults.stream()
- .map(MessageResult::getFlags)
- .map(keywordsFactory::fromFlags)
- .reduce(ACCUMULATOR)
- .get();
+ List<MailboxId> mailboxIds = getMailboxIds(messageResults);
+ Keywords keywords = getKeywords(messageResults);
return MetaDataWithContent.builderFromMessageResult(firstMessageResult)
.messageId(firstMessageResult.getMessageId())
@@ -144,14 +133,6 @@ public class MessageFullViewFactory {
.build();
}
- private boolean hasOnlyOneMessageId(Collection<MessageResult> messageResults) {
- return messageResults
- .stream()
- .map(MessageResult::getMessageId)
- .distinct()
- .count() == 1;
- }
-
private Instant getDateFromHeaderOrInternalDateOtherwise(org.apache.james.mime4j.dom.Message mimeMessage, MetaDataWithContent message) {
return Optional.ofNullable(mimeMessage.getDate())
.map(Date::toInstant)
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageMetadataViewFactory.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageMetadataViewFactory.java
new file mode 100644
index 0000000..95a382f
--- /dev/null
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageMetadataViewFactory.java
@@ -0,0 +1,57 @@
+/****************************************************************
+ * 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.jmap.draft.model.message.view;
+
+import java.util.Collection;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.james.jmap.draft.model.BlobId;
+import org.apache.james.mailbox.BlobManager;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MessageResult;
+
+public class MessageMetadataViewFactory implements MessageViewFactory<MessageMetadataView> {
+ private final BlobManager blobManager;
+
+ @Inject
+ MessageMetadataViewFactory(BlobManager blobManager) {
+ this.blobManager = blobManager;
+ }
+
+ @Override
+ public MessageMetadataView fromMessageResults(Collection<MessageResult> messageResults) throws MailboxException {
+ assertOneMessageId(messageResults);
+
+ MessageResult firstMessageResult = messageResults.iterator().next();
+ List<MailboxId> mailboxIds = getMailboxIds(messageResults);
+
+ return MessageMetadataView.messageMetadataBuilder()
+ .id(firstMessageResult.getMessageId())
+ .mailboxIds(mailboxIds)
+ .blobId(BlobId.of(blobManager.toBlobId(firstMessageResult.getMessageId())))
+ .threadId(firstMessageResult.getMessageId().serialize())
+ .keywords(getKeywords(messageResults))
+ .size(firstMessageResult.getSize())
+ .build();
+ }
+}
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java
new file mode 100644
index 0000000..5339c13
--- /dev/null
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java
@@ -0,0 +1,67 @@
+/****************************************************************
+ * 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.jmap.draft.model.message.view;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.james.jmap.draft.model.Keywords;
+import org.apache.james.jmap.draft.utils.KeywordsCombiner;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MessageResult;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Preconditions;
+
+public interface MessageViewFactory<T extends MessageView> {
+ KeywordsCombiner KEYWORDS_COMBINER = new KeywordsCombiner();
+ Keywords.KeywordsFactory KEYWORDS_FACTORY = Keywords.lenientFactory();
+
+ T fromMessageResults(Collection<MessageResult> messageResults) throws MailboxException;
+
+ default void assertOneMessageId(Collection<MessageResult> messageResults) {
+ Preconditions.checkArgument(!messageResults.isEmpty(), "MessageResults cannot be empty");
+ Preconditions.checkArgument(hasOnlyOneMessageId(messageResults), "MessageResults need to share the same messageId");
+ }
+
+ default boolean hasOnlyOneMessageId(Collection<MessageResult> messageResults) {
+ return messageResults
+ .stream()
+ .map(MessageResult::getMessageId)
+ .distinct()
+ .count() == 1;
+ }
+
+ default List<MailboxId> getMailboxIds(Collection<MessageResult> messageResults) {
+ return messageResults.stream()
+ .map(MessageResult::getMailboxId)
+ .distinct()
+ .collect(Guavate.toImmutableList());
+ }
+
+ default Keywords getKeywords(Collection<MessageResult> messageResults) {
+ return messageResults.stream()
+ .map(MessageResult::getFlags)
+ .map(KEYWORDS_FACTORY::fromFlags)
+ .reduce(KEYWORDS_COMBINER)
+ .get();
+ }
+}
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/message/view/MessageMetadataViewFactoryTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/message/view/MessageMetadataViewFactoryTest.java
new file mode 100644
index 0000000..36cac92
--- /dev/null
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/message/view/MessageMetadataViewFactoryTest.java
@@ -0,0 +1,110 @@
+/****************************************************************
+ * 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.jmap.draft.model.message.view;
+
+import java.util.List;
+
+import javax.mail.Flags;
+
+import org.apache.james.core.Username;
+import org.apache.james.jmap.draft.model.BlobId;
+import org.apache.james.jmap.draft.model.Keyword;
+import org.apache.james.jmap.draft.model.Keywords;
+import org.apache.james.jmap.draft.model.Number;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageIdManager;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
+import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.FetchGroupImpl;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.model.MessageResult;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableList;
+
+class MessageMetadataViewFactoryTest {
+
+ public static final Username BOB = Username.of("bob");
+ private MessageIdManager messageIdManager;
+ private MessageMetadataViewFactory testee;
+ private MailboxSession session;
+ private MessageManager bobInbox;
+ private MessageManager bobMailbox;
+ private ComposedMessageId message1;
+
+ @BeforeEach
+ void setUp() throws Exception {
+ InMemoryIntegrationResources resources = InMemoryIntegrationResources.defaultResources();
+ messageIdManager = resources.getMessageIdManager();
+ InMemoryMailboxManager mailboxManager = resources.getMailboxManager();
+
+ session = mailboxManager.createSystemSession(BOB);
+ MailboxId bobInboxId = mailboxManager.createMailbox(MailboxPath.inbox(session), session).get();
+ MailboxId bobMailboxId = mailboxManager.createMailbox(MailboxPath.forUser(BOB, "anotherMailbox"), session).get();
+
+ bobInbox = mailboxManager.getMailbox(bobInboxId, session);
+ bobMailbox = mailboxManager.getMailbox(bobMailboxId, session);
+
+ message1 = bobInbox.appendMessage(MessageManager.AppendCommand.builder()
+ .withFlags(new Flags(Flags.Flag.SEEN))
+ .build("header: value\r\n\r\nbody"),
+ session);
+
+ testee = new MessageMetadataViewFactory(resources.getBlobManager());
+ }
+
+ @Test
+ void fromMessageResultsShouldReturnCorrectView() throws Exception {
+ List<MessageResult> messages = messageIdManager
+ .getMessages(ImmutableList.of(message1.getMessageId()), FetchGroupImpl.MINIMAL, session);
+
+ MessageMetadataView actual = testee.fromMessageResults(messages);
+ SoftAssertions.assertSoftly(softly -> {
+ softly.assertThat(actual.getId()).isEqualTo(message1.getMessageId());
+ softly.assertThat(actual.getMailboxIds()).containsExactly(bobInbox.getId());
+ softly.assertThat(actual.getThreadId()).isEqualTo(message1.getMessageId().serialize());
+ softly.assertThat(actual.getSize()).isEqualTo(Number.fromLong(21));
+ softly.assertThat(actual.getKeywords()).isEqualTo(Keywords.strictFactory().from(Keyword.SEEN).asMap());
+ softly.assertThat(actual.getBlobId()).isEqualTo(BlobId.of(message1.getMessageId().serialize()));
+ });
+ }
+
+ @Test
+ void fromMessageResultsShouldCombineKeywords() throws Exception {
+ messageIdManager.setInMailboxes(message1.getMessageId(), ImmutableList.of(bobInbox.getId(), bobMailbox.getId()), session);
+ bobMailbox.setFlags(new Flags(Flags.Flag.FLAGGED), MessageManager.FlagsUpdateMode.REPLACE, MessageRange.all(), session);
+
+ List<MessageResult> messages = messageIdManager
+ .getMessages(ImmutableList.of(message1.getMessageId()), FetchGroupImpl.MINIMAL, session);
+
+ MessageMetadataView actual = testee.fromMessageResults(messages);
+ SoftAssertions.assertSoftly(softly -> {
+ softly.assertThat(actual.getId()).isEqualTo(message1.getMessageId());
+ softly.assertThat(actual.getKeywords()).isEqualTo(Keywords.strictFactory().from(Keyword.SEEN, Keyword.FLAGGED).asMap());
+ });
+ }
+
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org