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 ro...@apache.org on 2016/08/29 13:28:12 UTC

[15/17] james-project git commit: JAMES-1818 Remove store usage in message creation by using managers

JAMES-1818 Remove store usage in message creation by using managers


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/f1116e2d
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/f1116e2d
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/f1116e2d

Branch: refs/heads/master
Commit: f1116e2d5f406c893a08deec274e0797e498e903
Parents: 7bfb0cd
Author: Raphael Ouazana <ra...@linagora.com>
Authored: Thu Aug 25 09:41:54 2016 +0200
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Mon Aug 29 15:17:16 2016 +0200

----------------------------------------------------------------------
 .../apache/james/mailbox/MessageManager.java    |   6 +
 .../mailbox/store/StoreMessageManager.java      |  19 +-
 .../base/MailboxEventAnalyserTest.java          |   4 +
 .../integration/SetMessagesMethodTest.java      |   4 +-
 .../methods/SetMessagesCreationProcessor.java   |  93 +++---
 .../james/jmap/model/CreationMessage.java       |   6 +-
 .../apache/james/jmap/model/MessageFactory.java | 123 ++------
 .../model/message/DateResolutionFormater.java   |  66 -----
 .../james/jmap/model/message/EMailer.java       |  69 -----
 .../jmap/model/message/HeaderCollection.java    | 247 ----------------
 .../jmap/model/message/IndexableMessage.java    | 250 ----------------
 .../model/message/JsonMessageConstants.java     |  79 -----
 .../jmap/model/message/MessageUpdateJson.java   |  75 -----
 .../james/jmap/model/message/MimePart.java      | 292 -------------------
 .../model/message/MimePartContainerBuilder.java |  47 ---
 .../jmap/model/message/MimePartParser.java      | 121 --------
 .../message/RootMimePartContainerBuilder.java   |  89 ------
 .../org/apache/james/jmap/send/MailFactory.java |   6 +-
 .../jmap/utils/SystemMailboxesProvider.java     |   5 +-
 .../jmap/utils/SystemMailboxesProviderImpl.java |  30 +-
 .../SetMessagesCreationProcessorTest.java       |  98 +++----
 .../james/jmap/model/message/MimePartTest.java  | 249 ----------------
 .../apache/james/jmap/send/MailFactoryTest.java |  38 ++-
 23 files changed, 149 insertions(+), 1867 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
----------------------------------------------------------------------
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
index 2c6d8f0..92f3cae 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
@@ -31,6 +31,7 @@ import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.UnsupportedCriteriaException;
 import org.apache.james.mailbox.model.MailboxACL;
 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.apache.james.mailbox.model.MessageResult.FetchGroup;
@@ -171,6 +172,11 @@ public interface MessageManager {
     MailboxId getId();
     
     /**
+     * Gets the path of the referenced mailbox
+     */
+    MailboxPath getMailboxPath() throws MailboxException;
+    
+    /**
      * Gets current meta data for the mailbox.<br>
      * Consolidates common calls together to allow improved performance.<br>
      * The meta-data returned should be immutable and represent the current

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
index 1e6fb3c..f84daa9 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
@@ -53,6 +53,7 @@ import org.apache.james.mailbox.model.Attachment;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxACL.MailboxACLRights;
 import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.mailbox.model.MessageMetaData;
 import org.apache.james.mailbox.model.MessageRange;
@@ -249,7 +250,7 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana
      */
     public Iterator<Long> expunge(MessageRange set, MailboxSession mailboxSession) throws MailboxException {
         if (!isWriteable(mailboxSession)) {
-            throw new ReadOnlyException(new StoreMailboxPath(getMailboxEntity()), mailboxSession.getPathDelimiter());
+            throw new ReadOnlyException(getMailboxPath(), mailboxSession.getPathDelimiter());
         }
         Map<Long, MessageMetaData> uids = deleteMarkedInMailbox(set, mailboxSession);
 
@@ -271,7 +272,7 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana
         SharedFileInputStream contentIn = null;
 
         if (!isWriteable(mailboxSession)) {
-            throw new ReadOnlyException(new StoreMailboxPath(getMailboxEntity()), mailboxSession.getPathDelimiter());
+            throw new ReadOnlyException(getMailboxPath(), mailboxSession.getPathDelimiter());
         }
 
         try {
@@ -389,7 +390,7 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana
 
             new QuotaChecker(quotaManager, quotaRootResolver, mailbox).tryAddition(1, size);
 
-            return locker.executeWithLock(mailboxSession, new StoreMailboxPath(getMailboxEntity()), new MailboxPathLocker.LockAwareExecution<Long>() {
+            return locker.executeWithLock(mailboxSession, getMailboxPath(), new MailboxPathLocker.LockAwareExecution<Long>() {
 
                 @Override
                 public Long execute() throws MailboxException {
@@ -552,7 +553,7 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana
     public Map<Long, Flags> setFlags(final Flags flags, final FlagsUpdateMode flagsUpdateMode, final MessageRange set, MailboxSession mailboxSession) throws MailboxException {
 
         if (!isWriteable(mailboxSession)) {
-            throw new ReadOnlyException(new StoreMailboxPath(getMailboxEntity()), mailboxSession.getPathDelimiter());
+            throw new ReadOnlyException(getMailboxPath(), mailboxSession.getPathDelimiter());
         }
         final SortedMap<Long, Flags> newFlagsByUid = new TreeMap<Long, Flags>();
 
@@ -614,7 +615,7 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana
      */
     public List<MessageRange> moveTo(final MessageRange set, final StoreMessageManager toMailbox, final MailboxSession session) throws MailboxException {
         if (!isWriteable(session)) {
-            throw new ReadOnlyException(new StoreMailboxPath(getMailboxEntity()), session.getPathDelimiter());
+            throw new ReadOnlyException(getMailboxPath(), session.getPathDelimiter());
         }
         if (!toMailbox.isWriteable(session)) {
             throw new ReadOnlyException(new StoreMailboxPath(toMailbox.getMailboxEntity()), session.getPathDelimiter());
@@ -678,7 +679,7 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana
     protected List<Long> recent(final boolean reset, MailboxSession mailboxSession) throws MailboxException {
         if (reset) {
             if (!isWriteable(mailboxSession)) {
-                throw new ReadOnlyException(new StoreMailboxPath(getMailboxEntity()), mailboxSession.getPathDelimiter());
+                throw new ReadOnlyException(getMailboxPath(), mailboxSession.getPathDelimiter());
             }
         }
         final MessageMapper messageMapper = mapperFactory.getMessageMapper(mailboxSession);
@@ -835,7 +836,13 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana
         return aclResolver.applyGlobalACL(mailbox.getACL(), new GroupFolderResolver(mailboxSession).isGroupFolder(mailbox));
     }
     
+    @Override
     public MailboxId getId() {
         return mailbox.getMailboxId();
     }
+    
+    @Override
+    public MailboxPath getMailboxPath() throws MailboxException {
+        return new StoreMailboxPath(getMailboxEntity());
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/protocols/imap/src/test/java/org/apache/james/imap/processor/base/MailboxEventAnalyserTest.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/MailboxEventAnalyserTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/MailboxEventAnalyserTest.java
index 6d1eaac..1e8dfa2 100644
--- a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/MailboxEventAnalyserTest.java
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/MailboxEventAnalyserTest.java
@@ -330,6 +330,10 @@ public class MailboxEventAnalyserTest {
                 public MailboxId getId() {
                     return null;
                 }
+                
+                public MailboxPath getMailboxPath() {
+                    return null;
+                }
             };
         }
         

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
index 7fa3e83..d85c1bc 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java
@@ -1024,7 +1024,7 @@ public abstract class SetMessagesMethodTest {
             .body(NAME, equalTo("messagesSet"))
             .body(ARGUMENTS + ".created", aMapWithSize(1))
             .body(ARGUMENTS + ".created", hasKey(messageCreationId))
-            .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].headers.from", equalTo(fromAddress))
+            .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].headers.From", equalTo(fromAddress))
             .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].from.name", equalTo(fromAddress))
             .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].from.email", equalTo(fromAddress));
     }
@@ -1061,7 +1061,7 @@ public abstract class SetMessagesMethodTest {
             .body(NAME, equalTo("messagesSet"))
             .body(ARGUMENTS + ".created", aMapWithSize(1))
             .body(ARGUMENTS + ".created", hasKey(messageCreationId))
-            .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].headers.from", equalTo(fromAddress))
+            .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].headers.From", equalTo(fromAddress))
             .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].from.name", equalTo(fromAddress))
             .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].from.email", equalTo(fromAddress));
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java
index ebd299d..f270673 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesCreationProcessor.java
@@ -24,13 +24,11 @@ import java.util.Date;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
-import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.mail.Flags;
 import javax.mail.MessagingException;
-import javax.mail.internet.SharedInputStream;
 import javax.mail.util.SharedByteArrayInputStream;
 
 import org.apache.james.jmap.exceptions.AttachmentsNotFoundException;
@@ -42,6 +40,7 @@ import org.apache.james.jmap.model.CreationMessage;
 import org.apache.james.jmap.model.CreationMessageId;
 import org.apache.james.jmap.model.Message;
 import org.apache.james.jmap.model.MessageFactory;
+import org.apache.james.jmap.model.MessageFactory.MetaDataWithContent;
 import org.apache.james.jmap.model.MessageId;
 import org.apache.james.jmap.model.MessageProperties;
 import org.apache.james.jmap.model.MessageProperties.MessageProperty;
@@ -58,20 +57,13 @@ import org.apache.james.jmap.utils.SystemMailboxesProvider;
 import org.apache.james.lifecycle.api.LifecycleUtil;
 import org.apache.james.mailbox.AttachmentManager;
 import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.exception.AttachmentNotFoundException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.Cid;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageAttachment;
-import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
-import org.apache.james.mailbox.store.mail.MessageMapper;
-import org.apache.james.mailbox.store.mail.model.Mailbox;
-import org.apache.james.mailbox.store.mail.model.MailboxMessage;
-import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
-import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
 import org.apache.mailet.Mail;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -88,7 +80,6 @@ import com.google.common.collect.ImmutableList;
 public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     private static final Logger LOG = LoggerFactory.getLogger(SetMailboxesCreationProcessor.class);
-    private final MailboxSessionMapperFactory mailboxSessionMapperFactory;
     private final MIMEMessageConverter mimeMessageConverter;
     private final MailSpool mailSpool;
     private final MailFactory mailFactory;
@@ -98,14 +89,12 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     
     @VisibleForTesting @Inject
-    SetMessagesCreationProcessor(MailboxSessionMapperFactory mailboxSessionMapperFactory,
-                                 MIMEMessageConverter mimeMessageConverter,
+    SetMessagesCreationProcessor(MIMEMessageConverter mimeMessageConverter,
                                  MailSpool mailSpool,
                                  MailFactory mailFactory,
                                  MessageFactory messageFactory,
                                  SystemMailboxesProvider systemMailboxesProvider,
                                  AttachmentManager attachmentManager) {
-        this.mailboxSessionMapperFactory = mailboxSessionMapperFactory;
         this.mimeMessageConverter = mimeMessageConverter;
         this.mailSpool = mailSpool;
         this.mailFactory = mailFactory;
@@ -178,7 +167,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         }
     }
     
-    private void validateImplementedFeature(CreationMessageEntry entry, MailboxSession session) throws MailboxNotImplementedException {
+    private void validateImplementedFeature(CreationMessageEntry entry, MailboxSession session) throws MailboxException, MailboxNotImplementedException {
         if (isAppendToMailboxWithRole(Role.DRAFTS, entry.getValue(), session)) {
             throw new MailboxNotImplementedException("Drafts saving is not implemented");
         }
@@ -241,35 +230,21 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     
     private MessageWithId handleOutboxMessages(CreationMessageEntry entry, MailboxSession session) throws MailboxException, MessagingException {
-        Mailbox outbox = getMailboxWithRole(session, Role.OUTBOX).orElseThrow(() -> new MailboxNotFoundException(Role.OUTBOX.serialize()));
+        MessageManager outbox = getMailboxWithRole(session, Role.OUTBOX).orElseThrow(() -> new MailboxNotFoundException(Role.OUTBOX.serialize()));
         if (!isRequestForSending(entry.getValue(), session)) {
             throw new IllegalStateException("Messages for everything but outbox should have been filtered earlier");
         }
-        Function<Long, MessageId> idGenerator = uid -> generateMessageId(session, outbox, uid);
-        return createMessageInOutboxAndSend(entry, session, outbox, idGenerator);
+        MetaDataWithContent newMessage = createMessageInOutbox(entry, outbox, session);
+        return sendMessage(entry.getCreationId(), newMessage, session);
     }
     
-    @VisibleForTesting
-    protected MessageWithId createMessageInOutboxAndSend(CreationMessageEntry createdEntry,
-                                                           MailboxSession session,
-                                                           Mailbox outbox, Function<Long, MessageId> buildMessageIdFromUid) throws MailboxException, MessagingException {
-        
-        CreationMessageId creationId = createdEntry.getCreationId();
-        MessageMapper messageMapper = mailboxSessionMapperFactory.createMessageMapper(session);
-        MailboxMessage newMailboxMessage = buildMailboxMessage(session, createdEntry, outbox);
-        messageMapper.add(outbox, newMailboxMessage);
-        Message jmapMessage = messageFactory.fromMailboxMessage(newMailboxMessage, newMailboxMessage.getAttachments(), buildMessageIdFromUid);
-        sendMessage(newMailboxMessage, jmapMessage, session);
-        return new MessageWithId(creationId, jmapMessage);
-    }
-    
-    private boolean isAppendToMailboxWithRole(Role role, CreationMessage entry, MailboxSession mailboxSession) {
+    private boolean isAppendToMailboxWithRole(Role role, CreationMessage entry, MailboxSession mailboxSession) throws MailboxException {
         return getMailboxWithRole(mailboxSession, role)
                 .map(box -> entry.isIn(box))
                 .orElse(false);
     }
 
-    private Optional<Mailbox> getMailboxWithRole(MailboxSession mailboxSession, Role role) {
+    private Optional<MessageManager> getMailboxWithRole(MailboxSession mailboxSession, Role role) throws MailboxException {
         return systemMailboxesProvider.listMailboxes(role, mailboxSession).findFirst();
     }
     
@@ -295,29 +270,29 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
                 .collect(Collectors.toSet());
     }
 
-    private boolean isRequestForSending(CreationMessage creationMessage, MailboxSession session) {
+    private boolean isRequestForSending(CreationMessage creationMessage, MailboxSession session) throws MailboxException {
         return isAppendToMailboxWithRole(Role.OUTBOX, creationMessage, session);
     }
     
-    private MessageId generateMessageId(MailboxSession session, Mailbox outbox, long uid) {
-        MailboxPath outboxPath = new MailboxPath(session.getPersonalSpace(), session.getUser().getUserName(), outbox.getName());
-        return new MessageId(session.getUser(), outboxPath, uid);
-    }
-
-    private MailboxMessage buildMailboxMessage(MailboxSession session, MessageWithId.CreationMessageEntry createdEntry, Mailbox outbox) throws MailboxException {
+    private MetaDataWithContent createMessageInOutbox(MessageWithId.CreationMessageEntry createdEntry, MessageManager outbox, MailboxSession session) throws MailboxException {
         ImmutableList<MessageAttachment> messageAttachments = getMessageAttachments(session, createdEntry.getValue().getAttachments());
         byte[] messageContent = mimeMessageConverter.convert(createdEntry, messageAttachments);
-        SharedInputStream content = new SharedByteArrayInputStream(messageContent);
-        long size = messageContent.length;
-        int bodyStartOctet = 0;
-
-        Flags flags = getMessageFlags(createdEntry.getValue());
-        PropertyBuilder propertyBuilder = buildPropertyBuilder();
-        MailboxId mailboxId = outbox.getMailboxId();
+        SharedByteArrayInputStream content = new SharedByteArrayInputStream(messageContent);
         Date internalDate = Date.from(createdEntry.getValue().getDate().toInstant());
+        Flags flags = getMessageFlags(createdEntry.getValue());
 
-        return new SimpleMailboxMessage(internalDate, size,
-                bodyStartOctet, content, flags, propertyBuilder, mailboxId, messageAttachments);
+        long uid = outbox.appendMessage(content, internalDate, session, flags.contains(Flags.Flag.RECENT), flags);
+
+        return MetaDataWithContent.builder()
+                .uid(uid)
+                .flags(flags)
+                .size(messageContent.length)
+                .internalDate(internalDate)
+                .sharedContent(content)
+                .attachments(messageAttachments)
+                .mailboxId(outbox.getId())
+                .messageId(new MessageId(session.getUser(), outbox.getMailboxPath(), uid))
+                .build();
     }
 
     private ImmutableList<MessageAttachment> getMessageAttachments(MailboxSession session, ImmutableList<Attachment> attachments) throws MailboxException {
@@ -342,10 +317,6 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         }
     }
 
-    private PropertyBuilder buildPropertyBuilder() {
-        return new PropertyBuilder();
-    }
-
     private Flags getMessageFlags(CreationMessage message) {
         Flags result = new Flags();
         if (!message.isIsUnread()) {
@@ -363,8 +334,14 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         return result;
     }
 
-    private void sendMessage(MailboxMessage mailboxMessage, Message jmapMessage, MailboxSession session) throws MessagingException {
-        Mail mail = buildMessage(mailboxMessage, jmapMessage);
+    private MessageWithId sendMessage(CreationMessageId creationId, MetaDataWithContent message, MailboxSession session) throws MailboxException, MessagingException {
+        Message jmapMessage = messageFactory.fromMetaDataWithContent(message);
+        sendMessage(message, jmapMessage, session);
+        return new MessageWithId(creationId, jmapMessage);
+    }
+    
+    private void sendMessage(MetaDataWithContent message, Message jmapMessage, MailboxSession session) throws MessagingException {
+        Mail mail = buildMessage(message, jmapMessage);
         try {
             MailMetadata metadata = new MailMetadata(jmapMessage.getId(), session.getUser().getUserName());
             mailSpool.send(mail, metadata);
@@ -373,9 +350,9 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
         }
     }
 
-    private Mail buildMessage(MailboxMessage mailboxMessage, Message jmapMessage) throws MessagingException {
+    private Mail buildMessage(MetaDataWithContent message, Message jmapMessage) throws MessagingException {
         try {
-            return mailFactory.build(mailboxMessage, jmapMessage);
+            return mailFactory.build(message, jmapMessage);
         } catch (IOException e) {
             throw new MessagingException("error building message to send", e);
         }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java
index b925cc5..a113f83 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/CreationMessage.java
@@ -33,7 +33,7 @@ import javax.mail.internet.InternetAddress;
 
 import org.apache.james.jmap.methods.ValidationResult;
 import org.apache.james.jmap.model.MessageProperties.MessageProperty;
-import org.apache.james.mailbox.store.mail.model.Mailbox;
+import org.apache.james.mailbox.MessageManager;
 
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
@@ -361,8 +361,8 @@ public class CreationMessage {
         from.filter(f -> !f.hasValidEmail()).ifPresent(f -> errors.add(invalidPropertyFrom));
     }
 
-    public boolean isIn(Mailbox mailbox) {
-        return mailboxIds.contains(mailbox.getMailboxId().serialize());
+    public boolean isIn(MessageManager mailbox) {
+        return mailboxIds.contains(mailbox.getId().serialize());
     }
     
     @JsonDeserialize(builder = DraftEmailer.Builder.class)

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
index c92293c..c1597c2 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
@@ -27,26 +27,21 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.Set;
 import java.util.TimeZone;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.mail.Flags;
+import javax.mail.internet.SharedInputStream;
 
 import org.apache.james.jmap.model.MessageContentExtractor.MessageContent;
-import org.apache.james.jmap.model.message.EMailer;
-import org.apache.james.jmap.model.message.IndexableMessage;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.Cid;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.mailbox.model.MessageMetaData;
 import org.apache.james.mailbox.model.MessageResult;
-import org.apache.james.mailbox.store.extractor.DefaultTextExtractor;
-import org.apache.james.mailbox.store.mail.model.MailboxMessage;
 import org.apache.james.mime4j.dom.address.AddressList;
 import org.apache.james.mime4j.dom.address.Mailbox;
 import org.apache.james.mime4j.dom.address.MailboxList;
@@ -58,12 +53,10 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Multimap;
 import com.google.common.collect.Multimaps;
 
 public class MessageFactory {
 
-    public static final String MULTIVALUED_HEADERS_SEPARATOR = ", ";
     public static final ZoneId UTC_ZONE_ID = ZoneId.of("Z");
 
     private final MessagePreviewGenerator messagePreview;
@@ -123,38 +116,6 @@ public class MessageFactory {
         }
     }
 
-    public Message fromMailboxMessage(MailboxMessage mailboxMessage,
-            List<MessageAttachment> attachments,
-            Function<Long, MessageId> uidToMessageId) {
-
-        IndexableMessage im = IndexableMessage.from(mailboxMessage, new DefaultTextExtractor(), UTC_ZONE_ID);
-        MessageId messageId = uidToMessageId.apply(im.getId());
-        return Message.builder()
-                .id(messageId)
-                .blobId(BlobId.of(String.valueOf(im.getId())))
-                .threadId(messageId.serialize())
-                .mailboxIds(ImmutableList.of(im.getMailboxId()))
-                .inReplyToMessageId(getHeaderAsSingleValue(im, "in-reply-to"))
-                .isUnread(im.isUnRead())
-                .isFlagged(im.isFlagged())
-                .isAnswered(im.isAnswered())
-                .isDraft(im.isDraft())
-                .subject(getSubject(im))
-                .headers(toMap(im.getHeaders()))
-                .from(firstElasticSearchEmailers(im.getFrom()))
-                .to(fromElasticSearchEmailers(im.getTo()))
-                .cc(fromElasticSearchEmailers(im.getCc()))
-                .bcc(fromElasticSearchEmailers(im.getBcc()))
-                .replyTo(fromElasticSearchEmailers(im.getReplyTo()))
-                .size(im.getSize())
-                .date(getInternalDate(mailboxMessage, im))
-                .preview(getPreview(im))
-                .textBody(getTextBody(im))
-                .htmlBody(getHtmlBody(im))
-                .attachments(getAttachments(attachments))
-                .build();
-    }
-
     private String getPreview(MessageContent messageContent) {
         if (messageContent.getHtmlBody().isPresent()) {
             return messagePreview.forHTMLBody(messageContent.getHtmlBody());
@@ -162,21 +123,6 @@ public class MessageFactory {
         return messagePreview.forTextBody(messageContent.getTextBody());
     }
 
-    private String getPreview(IndexableMessage im) {
-        Optional<String> bodyHtml = im.getBodyHtml();
-        if (bodyHtml.isPresent()) {
-            return messagePreview.forHTMLBody(bodyHtml);
-        }
-        return messagePreview.forTextBody(im.getBodyText());
-    }
-
-    private String getSubject(IndexableMessage im) {
-        return im.getSubjects()
-                    .stream()
-                    .map(String::trim)
-                    .collect(Collectors.joining(MULTIVALUED_HEADERS_SEPARATOR));
-    }
-    
     private Emailer firstFromMailboxList(MailboxList list) {
         if (list == null) {
             return null;
@@ -211,34 +157,6 @@ public class MessageFactory {
         return mailbox.getAddress();
     }
 
-    private Emailer firstElasticSearchEmailers(Set<EMailer> emailers) {
-        return emailers.stream()
-                    .findFirst()
-                    .map(this::fromElasticSearchEmailer)
-                    .orElse(null);
-    }
-    
-    private ImmutableList<Emailer> fromElasticSearchEmailers(Set<EMailer> emailers) {
-        return emailers.stream()
-                    .map(this::fromElasticSearchEmailer)
-                    .collect(Guavate.toImmutableList());
-    }
-    
-    private Emailer fromElasticSearchEmailer(EMailer emailer) {
-        return Emailer.builder()
-                    .name(emailer.getName())
-                    .email(emailer.getAddress())
-                    .build();
-    }
-    
-    private ImmutableMap<String, String> toMap(Multimap<String, String> multimap) {
-        return multimap
-                .asMap()
-                .entrySet()
-                .stream()
-                .collect(Guavate.toImmutableMap(Map.Entry::getKey, x -> joinOnComma(x.getValue())));
-    }
-    
     private ImmutableMap<String, String> toMap(List<Field> fields) {
         Function<Entry<String, Collection<Field>>, String> bodyConcatenator = fieldListEntry -> fieldListEntry.getValue()
                 .stream()
@@ -261,26 +179,6 @@ public class MessageFactory {
         return field.getBody();
     }
     
-    private String getHeaderAsSingleValue(IndexableMessage im, String header) {
-        return Strings.emptyToNull(joinOnComma(im.getHeaders().get(header)));
-    }
-    
-    private String joinOnComma(Iterable<String> iterable) {
-        return String.join(MULTIVALUED_HEADERS_SEPARATOR, iterable);
-    }
-    
-    private ZonedDateTime getInternalDate(MailboxMessage mailboxMessage, IndexableMessage im) {
-        return ZonedDateTime.ofInstant(mailboxMessage.getInternalDate().toInstant(), UTC_ZONE_ID);
-    }
-
-    private String getTextBody(IndexableMessage im) {
-        return im.getBodyText().map(Strings::emptyToNull).orElse(null);
-    }
-
-    private String getHtmlBody(IndexableMessage im) {
-        return im.getBodyHtml().map(Strings::emptyToNull).orElse(null);
-    }
-
     private List<Attachment> getAttachments(List<MessageAttachment> attachments) {
         return attachments.stream()
                 .map(this::fromMailboxAttachment)
@@ -325,6 +223,7 @@ public class MessageFactory {
             private Long size;
             private Date internalDate;
             private InputStream content;
+            private SharedInputStream sharedContent;
             private List<MessageAttachment> attachments;
             private MailboxId mailboxId;
             private MessageId messageId;
@@ -359,6 +258,11 @@ public class MessageFactory {
                 return this;
             }
             
+            public Builder sharedContent(SharedInputStream sharedContent) {
+                this.sharedContent = sharedContent;
+                return this;
+            }
+            
             public Builder attachments(List<MessageAttachment> attachments) {
                 this.attachments = attachments;
                 return this;
@@ -382,11 +286,11 @@ public class MessageFactory {
                 Preconditions.checkArgument(flags != null);
                 Preconditions.checkArgument(size != null);
                 Preconditions.checkArgument(internalDate != null);
-                Preconditions.checkArgument(content != null);
+                Preconditions.checkArgument(content != null ^ sharedContent != null);
                 Preconditions.checkArgument(attachments != null);
                 Preconditions.checkArgument(mailboxId != null);
                 Preconditions.checkArgument(messageId != null);
-                return new MetaDataWithContent(uid, modSeq, flags, size, internalDate, content, attachments, mailboxId, messageId);
+                return new MetaDataWithContent(uid, modSeq, flags, size, internalDate, content, sharedContent, attachments, mailboxId, messageId);
             }
         }
 
@@ -396,17 +300,19 @@ public class MessageFactory {
         private final long size;
         private final Date internalDate;
         private final InputStream content;
+        private final SharedInputStream sharedContent;
         private final List<MessageAttachment> attachments;
         private final MailboxId mailboxId;
         private final MessageId messageId;
 
-        private MetaDataWithContent(long uid, long modSeq, Flags flags, long size, Date internalDate, InputStream content, List<MessageAttachment> attachments, MailboxId mailboxId, MessageId messageId) {
+        private MetaDataWithContent(long uid, long modSeq, Flags flags, long size, Date internalDate, InputStream content, SharedInputStream sharedContent, List<MessageAttachment> attachments, MailboxId mailboxId, MessageId messageId) {
             this.uid = uid;
             this.modSeq = modSeq;
             this.flags = flags;
             this.size = size;
             this.internalDate = internalDate;
             this.content = content;
+            this.sharedContent = sharedContent;
             this.attachments = attachments;
             this.mailboxId = mailboxId;
             this.messageId = messageId;
@@ -442,6 +348,11 @@ public class MessageFactory {
         }
 
         public InputStream getContent() {
+            if (sharedContent != null) {
+                long begin = 0;
+                long allContent = -1;
+                return sharedContent.newStream(begin, allContent);
+            }
             return content;
         }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/DateResolutionFormater.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/DateResolutionFormater.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/DateResolutionFormater.java
deleted file mode 100644
index e8baf74..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/DateResolutionFormater.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************
- * 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.model.message;
-
-import org.apache.james.mailbox.model.SearchQuery;
-
-import java.time.Instant;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.time.temporal.ChronoUnit;
-import java.time.temporal.TemporalUnit;
-import java.time.format.DateTimeFormatter;
-import java.util.Date;
-
-public class DateResolutionFormater {
-
-    public static DateTimeFormatter DATE_TIME_FOMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
-
-    public static ZonedDateTime computeUpperDate(ZonedDateTime date, SearchQuery.DateResolution resolution) {
-        return date.truncatedTo(convertDateResolutionField(resolution)).plus(1,convertDateResolutionField(resolution));
-    }
-
-    public static ZonedDateTime computeLowerDate(ZonedDateTime date, SearchQuery.DateResolution resolution) {
-        return date.truncatedTo(convertDateResolutionField(resolution));
-    }
-
-    private static TemporalUnit convertDateResolutionField(SearchQuery.DateResolution resolution) {
-        switch(resolution) {
-            case Year:
-                return ChronoUnit.YEARS;
-            case Month:
-                return ChronoUnit.MONTHS;
-            case Day:
-                return ChronoUnit.DAYS;
-            case Hour:
-                return ChronoUnit.HOURS;
-            case Minute:
-                return ChronoUnit.MINUTES;
-            case Second:
-                return ChronoUnit.SECONDS;
-            default:
-                throw new RuntimeException("Unknown Date resolution used");
-        }
-    }
-
-    public static ZonedDateTime convertDateToZonedDateTime(Date date) {
-        return ZonedDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/EMailer.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/EMailer.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/EMailer.java
deleted file mode 100644
index 0126c73..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/EMailer.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/****************************************************************
- * 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.model.message;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.MoreObjects;
-
-import java.util.Objects;
-
-public class EMailer {
-
-    private final String name;
-    private final String address;
-
-    public EMailer(String name, String address) {
-        this.name = name;
-        this.address = address;
-    }
-
-    @JsonProperty(JsonMessageConstants.EMailer.NAME)
-    public String getName() {
-        return name;
-    }
-
-    @JsonProperty(JsonMessageConstants.EMailer.ADDRESS)
-    public String getAddress() {
-        return address;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (o instanceof EMailer) {
-            EMailer otherEMailer = (EMailer) o;
-            return Objects.equals(name, otherEMailer.name)
-                && Objects.equals(address, otherEMailer.address);
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(name, address);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this)
-            .add("name", name)
-            .add("address", address)
-            .toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/HeaderCollection.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/HeaderCollection.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/HeaderCollection.java
deleted file mode 100644
index 03a99f2..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/HeaderCollection.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/****************************************************************
- * 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.model.message;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Charsets;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Multimap;
-import org.apache.james.mailbox.store.search.SearchUtil;
-import org.apache.james.mime4j.codec.DecoderUtil;
-import org.apache.james.mime4j.dom.address.Address;
-import org.apache.james.mime4j.dom.address.Group;
-import org.apache.james.mime4j.dom.address.Mailbox;
-import org.apache.james.mime4j.field.address.LenientAddressParser;
-import org.apache.james.mime4j.stream.Field;
-import org.apache.james.mime4j.util.MimeUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.HashSet;
-import java.util.Optional;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-public class HeaderCollection {
-
-    public static class Builder {
-
-        // Some sent e-mail have this form : Wed,  3 Jun 2015 09:05:46 +0000 (UTC)
-        // Java 8 Time library RFC_1123_DATE_TIME corresponds to Wed,  3 Jun 2015 09:05:46 +0000 only
-        // This REGEXP is here to match ( in order to remove ) the possible invalid end of a header date
-        // Example of matching patterns :
-        //  (UTC)
-        //  (CEST)
-        private static final Pattern DATE_SANITIZING_PATTERN = Pattern.compile(" *\\(.*\\) *");
-
-        private final Set<EMailer> toAddressSet;
-        private final Set<EMailer> fromAddressSet;
-        private final Set<EMailer> ccAddressSet;
-        private final Set<EMailer> bccAddressSet;
-        private final Set<EMailer> replyToAddressSet;
-        private final Set<String> subjectSet;
-        private final Multimap<String, String> headers;
-        private Optional<ZonedDateTime> sentDate;
-
-        private Builder() {
-            toAddressSet = new HashSet<>();
-            fromAddressSet = new HashSet<>();
-            ccAddressSet = new HashSet<>();
-            bccAddressSet = new HashSet<>();
-            replyToAddressSet = new HashSet<>();
-            subjectSet = new HashSet<>();
-            headers = ArrayListMultimap.create();
-            sentDate = Optional.empty();
-        }
-
-        public Builder add(Field field) {
-            Preconditions.checkNotNull(field);
-            String headerName = field.getName().toLowerCase();
-            String headerValue = DecoderUtil.decodeEncodedWords(field.getBody(), Charsets.ISO_8859_1);
-            headers.put(headerName, headerValue);
-            handleSpecificHeader(headerName, headerValue);
-            return this;
-        }
-
-        public HeaderCollection build() {
-            return new HeaderCollection(
-                ImmutableSet.copyOf(toAddressSet),
-                ImmutableSet.copyOf(fromAddressSet),
-                ImmutableSet.copyOf(ccAddressSet),
-                ImmutableSet.copyOf(bccAddressSet),
-                ImmutableSet.copyOf(replyToAddressSet),
-                ImmutableSet.copyOf(subjectSet),
-                ImmutableMultimap.copyOf(headers),
-                sentDate);
-        }
-
-        private void handleSpecificHeader(String headerName, String headerValue) {
-            switch (headerName) {
-                case TO:
-                case FROM:
-                case CC:
-                case BCC:
-                case REPLY_TO:
-                    manageAddressField(headerName, headerValue);
-                    break;
-                case SUBJECT:
-                    subjectSet.add(headerValue);
-                    break;
-                case DATE:
-                    sentDate = toISODate(headerValue);
-                    break;
-            }
-        }
-
-        private void manageAddressField(String headerName, String headerValue) {
-            LenientAddressParser.DEFAULT
-                .parseAddressList(MimeUtil.unfold(headerValue))
-                .stream()
-                .flatMap(this::convertAddressToMailboxStream)
-                .map((mailbox) -> new EMailer(SearchUtil.getDisplayAddress(mailbox) , mailbox.getAddress()))
-                .collect(Collectors.toCollection(() -> getAddressSet(headerName)));
-        }
-
-        private Stream<Mailbox> convertAddressToMailboxStream(Address address) {
-            if (address instanceof Mailbox) {
-                return Stream.of((Mailbox) address);
-            } else if (address instanceof Group) {
-                return ((Group) address).getMailboxes().stream();
-            }
-            return Stream.empty();
-        }
-
-        private Set<EMailer> getAddressSet(String headerName) {
-            switch (headerName) {
-                case TO:
-                    return toAddressSet;
-                case FROM:
-                    return fromAddressSet;
-                case CC:
-                    return ccAddressSet;
-                case BCC:
-                    return bccAddressSet;
-                case REPLY_TO:
-                    return replyToAddressSet;
-            }
-            throw new RuntimeException(headerName + " is not a address header name");
-        }
-
-        private Optional<ZonedDateTime> toISODate(String value) {
-            try {
-                return Optional.of(ZonedDateTime.parse(
-                    sanitizeDateStringHeaderValue(value),
-                    DateTimeFormatter.RFC_1123_DATE_TIME));
-            } catch (Exception e) {
-                LOGGER.info("Can not parse receive date " + value);
-                return Optional.empty();
-            }
-        }
-
-        @VisibleForTesting String sanitizeDateStringHeaderValue(String value) {
-            // Some sent e-mail have this form : Wed,  3 Jun 2015 09:05:46 +0000 (UTC)
-            // Java 8 Time library RFC_1123_DATE_TIME corresponds to Wed,  3 Jun 2015 09:05:46 +0000 only
-            // This method is here to convert the first date into something parsable by RFC_1123_DATE_TIME DateTimeFormatter
-            Matcher sanitizerMatcher = DATE_SANITIZING_PATTERN.matcher(value);
-            if (sanitizerMatcher.find()) {
-                return value.substring(0 , sanitizerMatcher.start());
-            }
-            return value;
-        }
-
-    }
-
-    public static final String TO = "to";
-    public static final String FROM = "from";
-    public static final String CC = "cc";
-    public static final String BCC = "bcc";
-    public static final String REPLY_TO = "reply-to";
-    public static final String SUBJECT = "subject";
-    public static final String DATE = "date";
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(HeaderCollection.class);
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    private final ImmutableSet<EMailer> toAddressSet;
-    private final ImmutableSet<EMailer> fromAddressSet;
-    private final ImmutableSet<EMailer> ccAddressSet;
-    private final ImmutableSet<EMailer> bccAddressSet;
-    private final ImmutableSet<EMailer> replyToAddressSet;
-    private final ImmutableSet<String> subjectSet;
-    private final ImmutableMultimap<String, String> headers;
-    private final Optional<ZonedDateTime> sentDate;
-
-    private HeaderCollection(ImmutableSet<EMailer> toAddressSet, ImmutableSet<EMailer> fromAddressSet,
-        ImmutableSet<EMailer> ccAddressSet, ImmutableSet<EMailer> bccAddressSet, ImmutableSet<EMailer> replyToAddressSet, ImmutableSet<String> subjectSet,
-        ImmutableMultimap<String, String> headers, Optional<ZonedDateTime> sentDate) {
-        this.toAddressSet = toAddressSet;
-        this.fromAddressSet = fromAddressSet;
-        this.ccAddressSet = ccAddressSet;
-        this.bccAddressSet = bccAddressSet;
-        this.replyToAddressSet = replyToAddressSet;
-        this.subjectSet = subjectSet;
-        this.headers = headers;
-        this.sentDate = sentDate;
-    }
-
-    public Set<EMailer> getToAddressSet() {
-        return toAddressSet;
-    }
-
-    public Set<EMailer> getFromAddressSet() {
-        return fromAddressSet;
-    }
-
-    public Set<EMailer> getCcAddressSet() {
-        return ccAddressSet;
-    }
-
-    public Set<EMailer> getBccAddressSet() {
-        return bccAddressSet;
-    }
-
-    public Set<EMailer> getReplyToAddressSet() {
-        return replyToAddressSet;
-    }
-
-    public Set<String> getSubjectSet() {
-        return subjectSet;
-    }
-
-    public Optional<ZonedDateTime> getSentDate() {
-        return sentDate;
-    }
-
-    public Multimap<String, String> getHeaders() {
-        return headers;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/IndexableMessage.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/IndexableMessage.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/IndexableMessage.java
deleted file mode 100644
index 972ac63..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/IndexableMessage.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/****************************************************************
- * 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.model.message;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import org.apache.james.mailbox.store.extractor.TextExtractor;
-import org.apache.james.mailbox.store.mail.model.MailboxMessage;
-import org.apache.james.mailbox.store.mail.model.Property;
-import org.apache.james.mime4j.MimeException;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Throwables;
-import com.google.common.collect.Multimap;
-
-public class IndexableMessage {
-
-    public static IndexableMessage from(MailboxMessage message, TextExtractor textExtractor, ZoneId zoneId) {
-        Preconditions.checkNotNull(message.getMailboxId());
-        IndexableMessage indexableMessage = new IndexableMessage();
-        try {
-            MimePart parsingResult = new MimePartParser(message, textExtractor).parse();
-            indexableMessage.bodyText = parsingResult.retrieveTextPlainBody();
-            indexableMessage.bodyHtml = parsingResult.retrieveTextHtmlBody();
-            indexableMessage.setFlattenedAttachments(parsingResult);
-            indexableMessage.copyHeaderFields(parsingResult.getHeaderCollection(), getSanitizedInternalDate(message, zoneId));
-            indexableMessage.copyMessageFields(message, zoneId);
-        } catch (IOException | MimeException e) {
-            throw Throwables.propagate(e);
-        }
-        return indexableMessage;
-    }
-
-    private void setFlattenedAttachments(MimePart parsingResult) {
-        attachments = parsingResult.getAttachmentsStream()
-            .collect(Collectors.toList());
-    }
-
-    private void copyHeaderFields(HeaderCollection headerCollection, ZonedDateTime internalDate) {
-        this.headers = headerCollection.getHeaders();
-        this.subjects = headerCollection.getSubjectSet();
-        this.from = headerCollection.getFromAddressSet();
-        this.to = headerCollection.getToAddressSet();
-        this.replyTo = headerCollection.getReplyToAddressSet();
-        this.cc = headerCollection.getCcAddressSet();
-        this.bcc = headerCollection.getBccAddressSet();
-        this.sentDate = DateResolutionFormater.DATE_TIME_FOMATTER.format(headerCollection.getSentDate().orElse(internalDate));
-    }
-
-    private void copyMessageFields(MailboxMessage message, ZoneId zoneId) {
-        this.id = message.getUid();
-        this.mailboxId = message.getMailboxId().serialize();
-        this.modSeq = message.getModSeq();
-        this.size = message.getFullContentOctets();
-        this.date = DateResolutionFormater.DATE_TIME_FOMATTER.format(getSanitizedInternalDate(message, zoneId));
-        this.isAnswered = message.isAnswered();
-        this.isDeleted = message.isDeleted();
-        this.isDraft = message.isDraft();
-        this.isFlagged = message.isFlagged();
-        this.isRecent = message.isRecent();
-        this.isUnRead = ! message.isSeen();
-        this.userFlags = message.createFlags().getUserFlags();
-        this.properties = message.getProperties();
-    }
-
-    private static ZonedDateTime getSanitizedInternalDate(MailboxMessage message, ZoneId zoneId) {
-        if (message.getInternalDate() == null) {
-            return ZonedDateTime.now();
-        }
-        return ZonedDateTime.ofInstant(
-            Instant.ofEpochMilli(message.getInternalDate().getTime()),
-            zoneId);
-    }
-
-    private Long id;
-    private String mailboxId;
-    private long modSeq;
-    private long size;
-    private String date;
-    private boolean isUnRead;
-    private boolean isRecent;
-    private boolean isFlagged;
-    private boolean isDeleted;
-    private boolean isDraft;
-    private boolean isAnswered;
-    private String[] userFlags;
-    private Multimap<String, String> headers;
-    private Set<EMailer> from;
-    private Set<EMailer> to;
-    private Set<EMailer> cc;
-    private Set<EMailer> bcc;
-    private Set<EMailer> replyTo;
-    private Set<String> subjects;
-    private String sentDate;
-    private List<Property> properties;
-    private List<MimePart> attachments;
-    private Optional<String> bodyText;
-    private Optional<String> bodyHtml;
-
-    @JsonProperty(JsonMessageConstants.ID)
-    public Long getId() {
-        return id;
-    }
-
-    @JsonProperty(JsonMessageConstants.MAILBOX_ID)
-    public String getMailboxId() {
-        return mailboxId;
-    }
-
-    @JsonProperty(JsonMessageConstants.MODSEQ)
-    public long getModSeq() {
-        return modSeq;
-    }
-
-    @JsonProperty(JsonMessageConstants.SIZE)
-    public long getSize() {
-        return size;
-    }
-
-    @JsonProperty(JsonMessageConstants.DATE)
-    public String getDate() {
-        return date;
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_UNREAD)
-    public boolean isUnRead() {
-        return isUnRead;
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_RECENT)
-    public boolean isRecent() {
-        return isRecent;
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_FLAGGED)
-    public boolean isFlagged() {
-        return isFlagged;
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_DELETED)
-    public boolean isDeleted() {
-        return isDeleted;
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_DRAFT)
-    public boolean isDraft() {
-        return isDraft;
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_ANSWERED)
-    public boolean isAnswered() {
-        return isAnswered;
-    }
-
-    @JsonProperty(JsonMessageConstants.USER_FLAGS)
-    public String[] getUserFlags() {
-        return userFlags;
-    }
-
-    @JsonProperty(JsonMessageConstants.HEADERS)
-    public Multimap<String, String> getHeaders() {
-        return headers;
-    }
-
-    @JsonProperty(JsonMessageConstants.SUBJECT)
-    public Set<String> getSubjects() {
-        return subjects;
-    }
-
-    @JsonProperty(JsonMessageConstants.FROM)
-    public Set<EMailer> getFrom() {
-        return from;
-    }
-
-    @JsonProperty(JsonMessageConstants.TO)
-    public Set<EMailer> getTo() {
-        return to;
-    }
-
-    @JsonProperty(JsonMessageConstants.CC)
-    public Set<EMailer> getCc() {
-        return cc;
-    }
-
-    @JsonProperty(JsonMessageConstants.BCC)
-    public Set<EMailer> getBcc() {
-        return bcc;
-    }
-
-    @JsonProperty(JsonMessageConstants.REPLY_TO)
-    public Set<EMailer> getReplyTo() {
-        return replyTo;
-    }
-
-    @JsonProperty(JsonMessageConstants.SENT_DATE)
-    public String getSentDate() {
-        return sentDate;
-    }
-
-    @JsonProperty(JsonMessageConstants.PROPERTIES)
-    public List<Property> getProperties() {
-        return properties;
-    }
-
-    @JsonProperty(JsonMessageConstants.ATTACHMENTS)
-    public List<MimePart> getAttachments() {
-        return attachments;
-    }
-
-    @JsonProperty(JsonMessageConstants.TEXT_BODY)
-    public Optional<String> getBodyText() {
-        return bodyText;
-    }
-
-    @JsonIgnore
-    public Optional<String> getBodyHtml() {
-        return bodyHtml;
-    }
-
-    @JsonProperty(JsonMessageConstants.HAS_ATTACHMENT)
-    public boolean getHasAttachment() {
-        return attachments.size() > 0;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/JsonMessageConstants.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/JsonMessageConstants.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/JsonMessageConstants.java
deleted file mode 100644
index 3123dc2..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/JsonMessageConstants.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/****************************************************************
- * 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.model.message;
-
-public interface JsonMessageConstants {
-
-    /*
-    Properties defined by JMAP
-     */
-    String ID = "id";
-    String MAILBOX_ID = "mailboxId";
-    String IS_UNREAD = "isUnread";
-    String IS_FLAGGED = "isFlagged";
-    String IS_ANSWERED = "isAnswered";
-    String IS_DRAFT = "isDraft";
-    String HEADERS = "headers";
-    String FROM = "from";
-    String TO = "to";
-    String CC = "cc";
-    String BCC = "bcc";
-    String REPLY_TO = "replyTo";
-    String SUBJECT = "subject";
-    String DATE = "date";
-    String SIZE = "size";
-    String TEXT_BODY = "textBody";
-    String SENT_DATE = "sentDate";
-    String ATTACHMENTS = "attachments";
-
-    /*
-    James properties we can easily get
-     */
-    String PROPERTIES = "properties";
-    String MODSEQ = "modSeq";
-    String USER_FLAGS = "userFlags";
-    String IS_RECENT = "isRecent";
-    String IS_DELETED = "isDeleted";
-    String MEDIA_TYPE = "mediaType";
-    String SUBTYPE = "subtype";
-    String HAS_ATTACHMENT = "hasAttachment";
-
-    interface EMailer {
-        String NAME = "name";
-        String ADDRESS = "address";
-    }
-
-    interface Attachment {
-        String TEXT_CONTENT = "textContent";
-        String MEDIA_TYPE = "mediaType";
-        String SUBTYPE = "subtype";
-        String CONTENT_DISPOSITION = "contentDisposition";
-        String FILENAME = "fileName";
-        String FILE_EXTENSION = "fileExtension";
-        String FILE_METADATA = "fileMetadata";
-    }
-
-    interface Property {
-        String NAMESPACE = "namespace";
-        String NAME = "name";
-        String VALUE = "value";
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MessageUpdateJson.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MessageUpdateJson.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MessageUpdateJson.java
deleted file mode 100644
index ede88a5..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MessageUpdateJson.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************
- * 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.model.message;
-
-import javax.mail.Flags;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-public class MessageUpdateJson {
-
-    private final Flags flags;
-    private final long modSeq;
-
-    public MessageUpdateJson(Flags flags, long modSeq) {
-        this.flags = flags;
-        this.modSeq = modSeq;
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_ANSWERED)
-    public boolean isAnswered() {
-        return flags.contains(Flags.Flag.ANSWERED);
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_DELETED)
-    public boolean isDeleted() {
-        return flags.contains(Flags.Flag.DELETED);
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_DRAFT)
-    public boolean isDraft() {
-        return flags.contains(Flags.Flag.DRAFT);
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_FLAGGED)
-    public boolean isFlagged() {
-        return flags.contains(Flags.Flag.FLAGGED);
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_RECENT)
-    public boolean isRecent() {
-        return flags.contains(Flags.Flag.RECENT);
-    }
-
-    @JsonProperty(JsonMessageConstants.IS_UNREAD)
-    public boolean isUnRead() {
-        return ! flags.contains(Flags.Flag.SEEN);
-    }
-
-
-    @JsonProperty(JsonMessageConstants.USER_FLAGS)
-    public String[] getUserFlags() {
-        return flags.getUserFlags();
-    }
-
-    @JsonProperty(JsonMessageConstants.MODSEQ)
-    public long getModSeq() {
-        return modSeq;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MimePart.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MimePart.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MimePart.java
deleted file mode 100644
index 7f573d3..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MimePart.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/****************************************************************
- * 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.model.message;
-
-import java.io.InputStream;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-import org.apache.commons.io.FilenameUtils;
-import org.apache.james.mailbox.store.extractor.DefaultTextExtractor;
-import org.apache.james.mailbox.store.extractor.ParsedContent;
-import org.apache.james.mailbox.store.extractor.TextExtractor;
-import org.apache.james.mime4j.stream.Field;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Multimap;
-
-public class MimePart {
-
-    private static final String HTML_SUBTYPE = "html";
-    private static final String PLAIN_SUBTYPE = "plain";
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static class Builder implements MimePartContainerBuilder {
-
-        private final HeaderCollection.Builder headerCollectionBuilder;
-        private Optional<InputStream> bodyContent;
-        private final List<MimePart> children;
-        private Optional<String> mediaType;
-        private Optional<String> subType;
-        private Optional<String> fileName;
-        private Optional<String> fileExtension;
-        private Optional<String> contentDisposition;
-        private TextExtractor textExtractor;
-
-        private Builder() {
-            children = Lists.newArrayList();
-            headerCollectionBuilder = HeaderCollection.builder();
-            this.bodyContent = Optional.empty();
-            this.mediaType = Optional.empty();
-            this.subType = Optional.empty();
-            this.fileName = Optional.empty();
-            this.fileExtension = Optional.empty();
-            this.contentDisposition = Optional.empty();
-            this.textExtractor = new DefaultTextExtractor();
-        }
-
-        @Override
-        public Builder addToHeaders(Field field) {
-            headerCollectionBuilder.add(field);
-            return this;
-        }
-
-        @Override
-        public Builder addBodyContent(InputStream bodyContent) {
-            this.bodyContent = Optional.of(bodyContent);
-            return this;
-        }
-
-        @Override
-        public Builder addChild(MimePart mimePart) {
-            children.add(mimePart);
-            return this;
-        }
-
-        @Override
-        public Builder addFileName(String fileName) {
-            this.fileName = Optional.ofNullable(fileName);
-            this.fileExtension = this.fileName.map(FilenameUtils::getExtension);
-            return this;
-        }
-
-        @Override
-        public Builder addMediaType(String mediaType) {
-            this.mediaType = Optional.ofNullable(mediaType);
-            return this;
-        }
-
-        @Override
-        public Builder addSubType(String subType) {
-            this.subType = Optional.ofNullable(subType);
-            return this;
-        }
-
-        @Override
-        public Builder addContentDisposition(String contentDisposition) {
-            this.contentDisposition = Optional.ofNullable(contentDisposition);
-            return this;
-        }
-
-        @Override
-        public MimePartContainerBuilder using(TextExtractor textExtractor) {
-            Preconditions.checkArgument(textExtractor != null, "Provided text extractor should not be null");
-            this.textExtractor = textExtractor;
-            return this;
-        }
-
-        @Override
-        public MimePart build() {
-            Optional<ParsedContent> parsedContent = parseContent(textExtractor);
-            return new MimePart(
-                headerCollectionBuilder.build(),
-                parsedContent.map( x -> Optional.ofNullable(x.getTextualContent()))
-                    .orElse(Optional.empty())
-                ,
-                mediaType,
-                subType,
-                fileName,
-                fileExtension,
-                contentDisposition,
-                children,
-                parsedContent
-                    .map(x -> x.getMetadata()
-                        .entrySet()
-                        .stream()
-                        .reduce(ImmutableMultimap.<String, String>builder(),
-                            (builder, entry) -> builder.putAll(entry.getKey(), entry.getValue()),
-                            (builder1, builder2) -> builder1.putAll(builder2.build())).build())
-                    .orElse(ImmutableMultimap.of())
-            );
-        }
-
-        private Optional<ParsedContent> parseContent(TextExtractor textExtractor) {
-            if (bodyContent.isPresent()) {
-                try {
-                    return Optional.of(textExtractor.extractContent(
-                        bodyContent.get(),
-                        computeContentType().orElse(null),
-                        fileName.orElse(null)));
-                } catch (Exception e) {
-                    LOGGER.warn("Failed parsing attachment", e);
-                }
-            }
-            return Optional.empty();
-        }
-
-        private Optional<String> computeContentType() {
-            if (mediaType.isPresent() && subType.isPresent()) {
-                return Optional.of(mediaType.get() + "/" + subType.get());
-            } else {
-                return Optional.empty();
-            }
-        }
-    }
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(MimePart.class);
-
-    private final HeaderCollection headerCollection;
-    private final Optional<String> bodyTextContent;
-    private final Optional<String> mediaType;
-    private final Optional<String> subType;
-    private final Optional<String> fileName;
-    private final Optional<String> fileExtension;
-    private final Optional<String> contentDisposition;
-    private final List<MimePart> attachments;
-    private final ImmutableMultimap<String, String> metadata;
-
-    private MimePart(HeaderCollection headerCollection, Optional<String> bodyTextContent, Optional<String> mediaType,
-                    Optional<String> subType, Optional<String> fileName, Optional<String> fileExtension,
-                    Optional<String> contentDisposition, List<MimePart> attachments, Multimap<String, String> metadata) {
-        this.headerCollection = headerCollection;
-        this.mediaType = mediaType;
-        this.subType = subType;
-        this.fileName = fileName;
-        this.fileExtension = fileExtension;
-        this.contentDisposition = contentDisposition;
-        this.attachments = attachments;
-        this.bodyTextContent = bodyTextContent;
-        this.metadata = ImmutableMultimap.copyOf(metadata);
-    }
-
-    @JsonIgnore
-    public List<MimePart> getAttachments() {
-        return attachments;
-    }
-
-    @JsonIgnore
-    public HeaderCollection getHeaderCollection() {
-        return headerCollection;
-    }
-
-    @JsonProperty(JsonMessageConstants.HEADERS)
-    public Multimap<String, String> getHeaders() {
-        return headerCollection.getHeaders();
-    }
-
-    @JsonProperty(JsonMessageConstants.Attachment.FILENAME)
-    public Optional<String> getFileName() {
-        return fileName;
-    }
-
-    @JsonProperty(JsonMessageConstants.Attachment.FILE_EXTENSION)
-    public Optional<String> getFileExtension() {
-        return fileExtension;
-    }
-
-    @JsonProperty(JsonMessageConstants.Attachment.MEDIA_TYPE)
-    public Optional<String> getMediaType() {
-        return mediaType;
-    }
-
-    @JsonProperty(JsonMessageConstants.Attachment.SUBTYPE)
-    public Optional<String> getSubType() {
-        return subType;
-    }
-
-    @JsonProperty(JsonMessageConstants.Attachment.CONTENT_DISPOSITION)
-    public Optional<String> getContentDisposition() {
-        return contentDisposition;
-    }
-
-    @JsonProperty(JsonMessageConstants.Attachment.TEXT_CONTENT)
-    public Optional<String> getTextualBody() {
-        return bodyTextContent;
-    }
-
-    @JsonProperty(JsonMessageConstants.Attachment.FILE_METADATA)
-    public ImmutableMultimap<String, String> getMetadata() {
-        return metadata;
-    }
-
-    @JsonIgnore
-    public Optional<String> retrieveTextHtmlBody() {
-        return retrieveTextBody(MimePart::isHTML);
-    }
-
-    @JsonIgnore
-    public Optional<String> retrieveTextPlainBody() {
-        return retrieveTextBody(MimePart::isPlain);
-    }
-
-    private Optional<String> retrieveTextBody(Predicate<MimePart> filter) {
-        return Stream.concat(
-                Stream.of(this),
-                getAttachmentsStream())
-            .filter(filter)
-            .map(MimePart::getTextualBody)
-            .filter(Optional::isPresent)
-            .map(Optional::get)
-            .findFirst();
-    }
-
-    @JsonIgnore
-    @VisibleForTesting boolean isHTML() {
-        return subType
-                .filter(HTML_SUBTYPE::equals)
-                .isPresent();
-    }
-
-    @JsonIgnore
-    @VisibleForTesting boolean isPlain() {
-        return subType
-                .filter(PLAIN_SUBTYPE::equals)
-                .isPresent();
-    }
-
-    @JsonIgnore
-    public Stream<MimePart> getAttachmentsStream() {
-        return attachments.stream()
-                .flatMap((mimePart) -> Stream.concat(Stream.of(mimePart), mimePart.getAttachmentsStream()));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f1116e2d/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MimePartContainerBuilder.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MimePartContainerBuilder.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MimePartContainerBuilder.java
deleted file mode 100644
index c9e671c..0000000
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/message/MimePartContainerBuilder.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/****************************************************************
- * 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.model.message;
-
-import org.apache.james.mailbox.store.extractor.TextExtractor;
-import org.apache.james.mime4j.stream.Field;
-
-import java.io.InputStream;
-
-public interface MimePartContainerBuilder {
-
-    MimePart build();
-
-    MimePartContainerBuilder using(TextExtractor textExtractor);
-
-    MimePartContainerBuilder addToHeaders(Field field);
-
-    MimePartContainerBuilder addBodyContent(InputStream bodyContent);
-
-    MimePartContainerBuilder addChild(MimePart mimePart);
-
-    MimePartContainerBuilder addFileName(String fileName);
-
-    MimePartContainerBuilder addMediaType(String mediaType);
-
-    MimePartContainerBuilder addSubType(String subType);
-
-    MimePartContainerBuilder addContentDisposition(String contentDisposition);
-
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org