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:48 UTC

[james-project] 05/22: JAMES-2987 Creating MessageHeaderView and MessageMetadataView

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 969d281d6c0d66e9c103cc45f629450fcae28e99
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Nov 21 10:16:18 2019 +0700

    JAMES-2987 Creating MessageHeaderView and MessageMetadataView
    
    Using `extends` and generics for both POJO and builder we got rid of
    code duplications
---
 .../draft/model/message/view/MessageFullView.java  | 242 +--------------------
 .../model/message/view/MessageHeaderView.java      | 201 +++++++++++++++++
 .../model/message/view/MessageMetadataView.java    | 169 ++++++++++++++
 3 files changed, 381 insertions(+), 231 deletions(-)

diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullView.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullView.java
index a84a271..01ab3a3 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullView.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullView.java
@@ -20,26 +20,21 @@
 package org.apache.james.jmap.draft.model.message.view;
 
 import java.time.Instant;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.Predicate;
 
-import org.apache.james.jmap.draft.methods.GetMessagesMethod;
 import org.apache.james.jmap.draft.methods.JmapResponseWriterImpl;
 import org.apache.james.jmap.draft.model.Attachment;
 import org.apache.james.jmap.draft.model.BlobId;
 import org.apache.james.jmap.draft.model.Emailer;
-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.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
 
 import com.fasterxml.jackson.annotation.JsonFilter;
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
 import com.google.common.annotations.VisibleForTesting;
@@ -50,129 +45,26 @@ import com.google.common.collect.ImmutableMap;
 
 @JsonDeserialize(builder = MessageFullView.Builder.class)
 @JsonFilter(JmapResponseWriterImpl.PROPERTIES_FILTER)
-public class MessageFullView implements MessageView {
+public class MessageFullView extends MessageHeaderView {
 
     public static Builder builder() {
         return new Builder();
     }
 
     @JsonPOJOBuilder(withPrefix = "")
-    public static class Builder {
-        private MessageId id;
-        private BlobId blobId;
-        private String threadId;
-        private ImmutableList<MailboxId> mailboxIds;
-        private String inReplyToMessageId;
-        private ImmutableMap<String, String> headers;
-        private Emailer from;
-        private final ImmutableList.Builder<Emailer> to;
-        private final ImmutableList.Builder<Emailer> cc;
-        private final ImmutableList.Builder<Emailer> bcc;
-        private final ImmutableList.Builder<Emailer> replyTo;
-        private String subject;
-        private Instant date;
-        private Number size;
+    public static class Builder extends MessageHeaderView.Builder<MessageFullView.Builder> {
         private String preview;
         private Optional<String> textBody = Optional.empty();
         private Optional<String> htmlBody = Optional.empty();
         private final ImmutableList.Builder<Attachment> attachments;
         private final ImmutableMap.Builder<BlobId, SubMessage> attachedMessages;
-        private Optional<Keywords> keywords = Optional.empty();
 
         private Builder() {
-            to = ImmutableList.builder();
-            cc = ImmutableList.builder();
-            bcc = ImmutableList.builder();
-            replyTo = ImmutableList.builder();
+            super();
             attachments = ImmutableList.builder();
             attachedMessages = ImmutableMap.builder();
         }
 
-        public Builder id(MessageId id) {
-            this.id = id;
-            return this;
-        }
-
-        public Builder blobId(BlobId blobId) {
-            this.blobId = blobId;
-            return this;
-        }
-
-        public Builder threadId(String threadId) {
-            this.threadId = threadId;
-            return this;
-        }
-
-        @JsonIgnore
-        public Builder mailboxId(MailboxId mailboxId) {
-            return this.fluentMailboxIds(mailboxId);
-        }
-
-        @JsonIgnore
-        public Builder fluentMailboxIds(MailboxId... mailboxIds) {
-            return this.mailboxIds(Arrays.asList((mailboxIds)));
-        }
-
-        public Builder mailboxIds(Collection<MailboxId> mailboxIds) {
-            this.mailboxIds = ImmutableList.copyOf(mailboxIds);
-            return this;
-        }
-
-        public Builder inReplyToMessageId(String inReplyToMessageId) {
-            this.inReplyToMessageId = inReplyToMessageId;
-            return this;
-        }
-
-        public Builder keywords(Keywords keywords) {
-            this.keywords = Optional.ofNullable(keywords);
-            return this;
-        }
-
-        public Builder headers(ImmutableMap<String, String> headers) {
-            this.headers = headers;
-            return this;
-        }
-
-        public Builder from(Emailer from) {
-            this.from = from;
-            return this;
-        }
-
-        public Builder to(List<Emailer> to) {
-            this.to.addAll(to);
-            return this;
-        }
-
-        public Builder cc(List<Emailer> cc) {
-            this.cc.addAll(cc);
-            return this;
-        }
-
-        public Builder bcc(List<Emailer> bcc) {
-            this.bcc.addAll(bcc);
-            return this;
-        }
-
-        public Builder replyTo(List<Emailer> replyTo) {
-            this.replyTo.addAll(replyTo);
-            return this;
-        }
-
-        public Builder subject(String subject) {
-            this.subject = subject;
-            return this;
-        }
-
-        public Builder date(Instant date) {
-            this.date = date;
-            return this;
-        }
-
-        public Builder size(long size) {
-            this.size = Number.BOUND_SANITIZING_FACTORY.from(size);
-            return this;
-        }
-
         public Builder preview(String preview) {
             this.preview = preview;
             return this;
@@ -199,17 +91,9 @@ public class MessageFullView implements MessageView {
         }
 
         public MessageFullView build() {
-            Preconditions.checkState(id != null, "'id' is mandatory");
-            Preconditions.checkState(blobId != null, "'blobId' is mandatory");
-            Preconditions.checkState(!Strings.isNullOrEmpty(threadId), "'threadId' is mandatory");
-            Preconditions.checkState(mailboxIds != null, "'mailboxIds' is mandatory");
-            Preconditions.checkState(headers != null, "'headers' is mandatory");
-            Preconditions.checkState(size != null, "'size' is mandatory");
-            Preconditions.checkState(date != null, "'date' is mandatory");
-            Preconditions.checkState(!Strings.isNullOrEmpty(preview), "'preview' is mandatory");
             ImmutableList<Attachment> attachments = this.attachments.build();
             ImmutableMap<BlobId, SubMessage> attachedMessages = this.attachedMessages.build();
-            Preconditions.checkState(areAttachedMessagesKeysInAttachments(attachments, attachedMessages), "'attachedMessages' keys must be in 'attachements'");
+            checkState(attachments, attachedMessages);
             boolean hasAttachment = hasAttachment(attachments);
 
             return new MessageFullView(id, blobId, threadId, mailboxIds, Optional.ofNullable(inReplyToMessageId),
@@ -217,6 +101,12 @@ public class MessageFullView implements MessageView {
                 to.build(), cc.build(), bcc.build(), replyTo.build(), subject, date, size, preview, textBody, htmlBody, attachments, attachedMessages,
                 keywords.orElse(Keywords.DEFAULT_VALUE));
         }
+
+        public void checkState(ImmutableList<Attachment> attachments, ImmutableMap<BlobId, SubMessage> attachedMessages) {
+            super.checkState();
+            Preconditions.checkState(!Strings.isNullOrEmpty(preview), "'preview' is mandatory");
+            Preconditions.checkState(areAttachedMessagesKeysInAttachments(attachments, attachedMessages), "'attachedMessages' keys must be in 'attachements'");
+        }
     }
 
     protected static boolean areAttachedMessagesKeysInAttachments(ImmutableList<Attachment> attachments, ImmutableMap<BlobId, SubMessage> attachedMessages) {
@@ -235,28 +125,12 @@ public class MessageFullView implements MessageView {
                 .anyMatch(attachment -> !attachment.isInlinedWithCid());
     }
 
-    private final MessageId id;
-    private final BlobId blobId;
-    private final String threadId;
-    private final ImmutableList<MailboxId> mailboxIds;
-    private final Optional<String> inReplyToMessageId;
     private final boolean hasAttachment;
-    @JsonFilter(GetMessagesMethod.HEADERS_FILTER)
-    private final ImmutableMap<String, String> headers;
-    private final Optional<Emailer> from;
-    private final ImmutableList<Emailer> to;
-    private final ImmutableList<Emailer> cc;
-    private final ImmutableList<Emailer> bcc;
-    private final ImmutableList<Emailer> replyTo;
-    private final String subject;
-    private final Instant date;
-    private final Number size;
     private final String preview;
     private final Optional<String> textBody;
     private final Optional<String> htmlBody;
     private final ImmutableList<Attachment> attachments;
     private final ImmutableMap<BlobId, SubMessage> attachedMessages;
-    private final Keywords keywords;
 
     @VisibleForTesting
     MessageFullView(MessageId id,
@@ -280,109 +154,19 @@ public class MessageFullView implements MessageView {
                     ImmutableList<Attachment> attachments,
                     ImmutableMap<BlobId, SubMessage> attachedMessages,
                     Keywords keywords) {
-        this.id = id;
-        this.blobId = blobId;
-        this.threadId = threadId;
-        this.mailboxIds = mailboxIds;
-        this.inReplyToMessageId = inReplyToMessageId;
+        super(id, blobId, threadId, mailboxIds, inReplyToMessageId, headers, from, to, cc, bcc, replyTo, subject, date, size, keywords);
         this.hasAttachment = hasAttachment;
-        this.headers = headers;
-        this.from = from;
-        this.to = to;
-        this.cc = cc;
-        this.bcc = bcc;
-        this.replyTo = replyTo;
-        this.subject = subject;
-        this.date = date;
-        this.size = size;
         this.preview = preview;
         this.textBody = textBody;
         this.htmlBody = htmlBody;
         this.attachments = attachments;
         this.attachedMessages = attachedMessages;
-        this.keywords = keywords;
-    }
-
-    public MessageId getId() {
-        return id;
-    }
-
-    public BlobId getBlobId() {
-        return blobId;
-    }
-
-    public String getThreadId() {
-        return threadId;
-    }
-
-    public ImmutableList<MailboxId> getMailboxIds() {
-        return mailboxIds;
-    }
-
-    public Optional<String> getInReplyToMessageId() {
-        return inReplyToMessageId;
-    }
-
-    public boolean isIsUnread() {
-        return !keywords.contains(Keyword.SEEN);
-    }
-
-    public boolean isIsFlagged() {
-        return keywords.contains(Keyword.FLAGGED);
-    }
-
-    public boolean isIsAnswered() {
-        return keywords.contains(Keyword.ANSWERED);
-    }
-
-    public boolean isIsDraft() {
-        return keywords.contains(Keyword.DRAFT);
-    }
-
-    public boolean isIsForwarded() {
-        return keywords.contains(Keyword.FORWARDED);
     }
 
     public boolean isHasAttachment() {
         return hasAttachment;
     }
 
-    public ImmutableMap<String, String> getHeaders() {
-        return headers;
-    }
-
-    public Optional<Emailer> getFrom() {
-        return from;
-    }
-
-    public ImmutableList<Emailer> getTo() {
-        return to;
-    }
-
-    public ImmutableList<Emailer> getCc() {
-        return cc;
-    }
-
-    public ImmutableList<Emailer> getBcc() {
-        return bcc;
-    }
-
-    public ImmutableList<Emailer> getReplyTo() {
-        return replyTo;
-    }
-
-    public String getSubject() {
-        return subject;
-    }
-
-    public Instant getDate() {
-        return date;
-    }
-
-    public Number getSize() {
-        return size;
-    }
-
     public String getPreview() {
         return preview;
     }
@@ -402,8 +186,4 @@ public class MessageFullView implements MessageView {
     public ImmutableMap<BlobId, SubMessage> getAttachedMessages() {
         return attachedMessages;
     }
-
-    public ImmutableMap<String, Boolean> getKeywords() {
-        return keywords.asMap();
-    }
 }
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java
new file mode 100644
index 0000000..abb3a31
--- /dev/null
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java
@@ -0,0 +1,201 @@
+/****************************************************************
+ * 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.time.Instant;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.james.jmap.draft.methods.GetMessagesMethod;
+import org.apache.james.jmap.draft.model.BlobId;
+import org.apache.james.jmap.draft.model.Emailer;
+import org.apache.james.jmap.draft.model.Keywords;
+import org.apache.james.jmap.draft.model.Number;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MessageId;
+
+import com.fasterxml.jackson.annotation.JsonFilter;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class MessageHeaderView extends MessageMetadataView {
+
+    public static Builder messageHeaderBuilder() {
+        return new Builder();
+    }
+
+    public static class Builder<S extends MessageHeaderView.Builder<S>> extends MessageMetadataView.Builder<S> {
+        protected String inReplyToMessageId;
+        protected ImmutableMap<String, String> headers;
+        protected Emailer from;
+        protected final ImmutableList.Builder<Emailer> to;
+        protected final ImmutableList.Builder<Emailer> cc;
+        protected final ImmutableList.Builder<Emailer> bcc;
+        protected final ImmutableList.Builder<Emailer> replyTo;
+        protected String subject;
+        protected Instant date;
+
+        protected Builder() {
+            super();
+            to = ImmutableList.builder();
+            cc = ImmutableList.builder();
+            bcc = ImmutableList.builder();
+            replyTo = ImmutableList.builder();
+        }
+
+        public S inReplyToMessageId(String inReplyToMessageId) {
+            this.inReplyToMessageId = inReplyToMessageId;
+            return (S) this;
+        }
+
+        public S headers(ImmutableMap<String, String> headers) {
+            this.headers = headers;
+            return (S) this;
+        }
+
+        public S from(Emailer from) {
+            this.from = from;
+            return (S) this;
+        }
+
+        public S to(List<Emailer> to) {
+            this.to.addAll(to);
+            return (S) this;
+        }
+
+        public S cc(List<Emailer> cc) {
+            this.cc.addAll(cc);
+            return (S) this;
+        }
+
+        public S bcc(List<Emailer> bcc) {
+            this.bcc.addAll(bcc);
+            return (S) this;
+        }
+
+        public S replyTo(List<Emailer> replyTo) {
+            this.replyTo.addAll(replyTo);
+            return (S) this;
+        }
+
+        public S subject(String subject) {
+            this.subject = subject;
+            return (S) this;
+        }
+
+        public S date(Instant date) {
+            this.date = date;
+            return (S) this;
+        }
+
+        public MessageHeaderView build() {
+            checkState();
+
+            return new MessageHeaderView(id, blobId, threadId, mailboxIds, Optional.ofNullable(inReplyToMessageId),
+                headers, Optional.ofNullable(from),
+                to.build(), cc.build(), bcc.build(), replyTo.build(), subject, date, size,
+                keywords.orElse(Keywords.DEFAULT_VALUE));
+        }
+
+        @Override
+        protected void checkState() {
+            super.checkState();
+            Preconditions.checkState(headers != null, "'headers' is mandatory");
+            Preconditions.checkState(date != null, "'date' is mandatory");
+        }
+    }
+
+    private final Optional<String> inReplyToMessageId;
+    @JsonFilter(GetMessagesMethod.HEADERS_FILTER)
+    private final ImmutableMap<String, String> headers;
+    private final Optional<Emailer> from;
+    private final ImmutableList<Emailer> to;
+    private final ImmutableList<Emailer> cc;
+    private final ImmutableList<Emailer> bcc;
+    private final ImmutableList<Emailer> replyTo;
+    private final String subject;
+    private final Instant date;
+
+    @VisibleForTesting
+    MessageHeaderView(MessageId id,
+                      BlobId blobId,
+                      String threadId,
+                      ImmutableList<MailboxId> mailboxIds,
+                      Optional<String> inReplyToMessageId,
+                      ImmutableMap<String, String> headers,
+                      Optional<Emailer> from,
+                      ImmutableList<Emailer> to,
+                      ImmutableList<Emailer> cc,
+                      ImmutableList<Emailer> bcc,
+                      ImmutableList<Emailer> replyTo,
+                      String subject,
+                      Instant date,
+                      Number size,
+                      Keywords keywords) {
+        super(id, blobId, threadId, mailboxIds, size, keywords);
+        this.inReplyToMessageId = inReplyToMessageId;
+        this.headers = headers;
+        this.from = from;
+        this.to = to;
+        this.cc = cc;
+        this.bcc = bcc;
+        this.replyTo = replyTo;
+        this.subject = subject;
+        this.date = date;
+    }
+
+    public Optional<String> getInReplyToMessageId() {
+        return inReplyToMessageId;
+    }
+
+    public ImmutableMap<String, String> getHeaders() {
+        return headers;
+    }
+
+    public Optional<Emailer> getFrom() {
+        return from;
+    }
+
+    public ImmutableList<Emailer> getTo() {
+        return to;
+    }
+
+    public ImmutableList<Emailer> getCc() {
+        return cc;
+    }
+
+    public ImmutableList<Emailer> getBcc() {
+        return bcc;
+    }
+
+    public ImmutableList<Emailer> getReplyTo() {
+        return replyTo;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public Instant getDate() {
+        return date;
+    }
+}
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageMetadataView.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageMetadataView.java
new file mode 100644
index 0000000..c7d599e
--- /dev/null
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageMetadataView.java
@@ -0,0 +1,169 @@
+/****************************************************************
+ * 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.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+
+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.model.MailboxId;
+import org.apache.james.mailbox.model.MessageId;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class MessageMetadataView implements MessageView {
+
+    public static Builder messageMetadataBuilder() {
+        return new Builder();
+    }
+
+    public static class Builder<S extends Builder<S>> {
+        protected MessageId id;
+        protected BlobId blobId;
+        protected String threadId;
+        protected ImmutableList<MailboxId> mailboxIds;
+        protected Number size;
+        protected Optional<Keywords> keywords = Optional.empty();
+
+        public S id(MessageId id) {
+            this.id = id;
+            return (S) this;
+        }
+
+        public S blobId(BlobId blobId) {
+            this.blobId = blobId;
+            return (S) this;
+        }
+
+        public S threadId(String threadId) {
+            this.threadId = threadId;
+            return (S) this;
+        }
+
+        @JsonIgnore
+        public S mailboxId(MailboxId mailboxId) {
+            return this.fluentMailboxIds(mailboxId);
+        }
+
+        @JsonIgnore
+        public S fluentMailboxIds(MailboxId... mailboxIds) {
+            return this.mailboxIds(Arrays.asList((mailboxIds)));
+        }
+
+        public S mailboxIds(Collection<MailboxId> mailboxIds) {
+            this.mailboxIds = ImmutableList.copyOf(mailboxIds);
+            return (S) this;
+        }
+
+        public S keywords(Keywords keywords) {
+            this.keywords = Optional.ofNullable(keywords);
+            return (S) this;
+        }
+
+        public S size(long size) {
+            this.size = Number.BOUND_SANITIZING_FACTORY.from(size);
+            return (S) this;
+        }
+
+        public MessageMetadataView build() {
+            checkState();
+
+            return new MessageMetadataView(id, blobId, threadId, mailboxIds, size, keywords.orElse(Keywords.DEFAULT_VALUE));
+        }
+
+        protected void checkState() {
+            Preconditions.checkState(id != null, "'id' is mandatory");
+            Preconditions.checkState(blobId != null, "'blobId' is mandatory");
+            Preconditions.checkState(!Strings.isNullOrEmpty(threadId), "'threadId' is mandatory");
+            Preconditions.checkState(mailboxIds != null, "'mailboxIds' is mandatory");
+            Preconditions.checkState(size != null, "'size' is mandatory");
+        }
+    }
+
+    private final MessageId id;
+    private final BlobId blobId;
+    private final String threadId;
+    private final ImmutableList<MailboxId> mailboxIds;
+    private final Number size;
+    private final Keywords keywords;
+
+    @VisibleForTesting
+    MessageMetadataView(MessageId id, BlobId blobId, String threadId, ImmutableList<MailboxId> mailboxIds, Number size, Keywords keywords) {
+        this.id = id;
+        this.blobId = blobId;
+        this.threadId = threadId;
+        this.mailboxIds = mailboxIds;
+        this.size = size;
+        this.keywords = keywords;
+    }
+
+    public MessageId getId() {
+        return id;
+    }
+
+    public BlobId getBlobId() {
+        return blobId;
+    }
+
+    public String getThreadId() {
+        return threadId;
+    }
+
+    public ImmutableList<MailboxId> getMailboxIds() {
+        return mailboxIds;
+    }
+
+    public boolean isIsUnread() {
+        return !keywords.contains(Keyword.SEEN);
+    }
+
+    public boolean isIsFlagged() {
+        return keywords.contains(Keyword.FLAGGED);
+    }
+
+    public boolean isIsAnswered() {
+        return keywords.contains(Keyword.ANSWERED);
+    }
+
+    public boolean isIsDraft() {
+        return keywords.contains(Keyword.DRAFT);
+    }
+
+    public boolean isIsForwarded() {
+        return keywords.contains(Keyword.FORWARDED);
+    }
+
+    public Number getSize() {
+        return size;
+    }
+
+    public ImmutableMap<String, Boolean> getKeywords() {
+        return keywords.asMap();
+    }
+}


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