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 bt...@apache.org on 2017/03/23 09:12:17 UTC

[1/6] james-project git commit: JAMES-1965 Compute textBody when htmlBody is available

Repository: james-project
Updated Branches:
  refs/heads/master b119f624d -> 844b9519c


JAMES-1965 Compute textBody when htmlBody is available


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

Branch: refs/heads/master
Commit: 0678047b004eece18a258c9a7741610d2f703e2f
Parents: b119f62
Author: Quynh Nguyen <qn...@linagora.com>
Authored: Wed Mar 15 11:04:48 2017 +0700
Committer: Quynh Nguyen <qn...@linagora.com>
Committed: Thu Mar 23 16:02:45 2017 +0700

----------------------------------------------------------------------
 .../apache/james/jmap/model/MessageFactory.java | 37 +++++++++++---
 .../SetMessagesCreationProcessorTest.java       |  4 +-
 .../james/jmap/model/MessageFactoryTest.java    | 53 +++++++++++++++++++-
 .../apache/james/jmap/send/MailFactoryTest.java |  4 +-
 4 files changed, 88 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/0678047b/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 9dc1acf..5d7b2fa 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
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.james.jmap.model;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.time.ZoneId;
@@ -27,6 +28,7 @@ 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;
@@ -39,6 +41,7 @@ import javax.mail.internet.SharedInputStream;
 import org.apache.james.jmap.model.MessageContentExtractor.MessageContent;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extractor.TextExtractor;
 import org.apache.james.mailbox.model.Cid;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageAttachment;
@@ -63,21 +66,30 @@ public class MessageFactory {
 
     private static final int NO_LINE_LENGTH_LIMIT_PARSING = -1;
 
-    public static final ZoneId UTC_ZONE_ID = ZoneId.of("Z");
+    private static final ZoneId UTC_ZONE_ID = ZoneId.of("Z");
+
+    private static final String HTML_CONTENT = "text/html";
+
+    private static final String EMPTY_FILE_NAME = "";
+
+    private static final String NO_BODY = "";
 
     private final MessagePreviewGenerator messagePreview;
     private final MessageContentExtractor messageContentExtractor;
+    private final TextExtractor textExtractor;
 
     @Inject
-    public MessageFactory(MessagePreviewGenerator messagePreview, MessageContentExtractor messageContentExtractor) {
+    public MessageFactory(MessagePreviewGenerator messagePreview, MessageContentExtractor messageContentExtractor, TextExtractor textExtractor) {
         this.messagePreview = messagePreview;
         this.messageContentExtractor = messageContentExtractor;
+        this.textExtractor = textExtractor;
     }
 
     public Message fromMetaDataWithContent(MetaDataWithContent message) throws MailboxException {
         org.apache.james.mime4j.dom.Message mimeMessage = parse(message);
         MessageContent messageContent = extractContent(mimeMessage);
-
+        String htmlBody = messageContent.getHtmlBody().orElse(NO_BODY);
+        String textBody = messageContent.getTextBody().orElseGet(() -> textBodyFromHtmlBody(htmlBody).orElse(NO_BODY));
         return Message.builder()
                 .id(message.getMessageId())
                 .blobId(BlobId.of(String.valueOf(message.getUid().asLong())))
@@ -97,13 +109,21 @@ public class MessageFactory {
                 .replyTo(fromAddressList(mimeMessage.getReplyTo()))
                 .size(message.getSize())
                 .date(message.getInternalDateAsZonedDateTime())
-                .textBody(messageContent.getTextBody().orElse(null))
-                .htmlBody(messageContent.getHtmlBody().orElse(null))
-                .preview(getPreview(messageContent))
+                .textBody(textBody)
+                .htmlBody(htmlBody)
+                .preview(getPreview(messageContent, textBody))
                 .attachments(getAttachments(message.getAttachments()))
                 .build();
     }
 
+    private Optional<String> textBodyFromHtmlBody(String htmlBody) {
+        try {
+            return Optional.of(textExtractor.extractContent(new ByteArrayInputStream(htmlBody.getBytes()), HTML_CONTENT, EMPTY_FILE_NAME).getTextualContent());
+        } catch (Exception e) {
+            return Optional.empty();
+        }
+    }
+
     private org.apache.james.mime4j.dom.Message parse(MetaDataWithContent message) throws MailboxException {
         try {
             return MessageBuilder
@@ -125,8 +145,11 @@ public class MessageFactory {
         }
     }
 
-    private String getPreview(MessageContent messageContent) {
+    private String getPreview(MessageContent messageContent, String computedTextBody) {
         if (messageContent.getHtmlBody().isPresent()) {
+            if (!messageContent.getTextBody().isPresent()) {
+                return messagePreview.forTextBody(Optional.of(computedTextBody));
+            }
             return messagePreview.forHTMLBody(messageContent.getHtmlBody());
         }
         return messagePreview.forTextBody(messageContent.getTextBody());

http://git-wip-us.apache.org/repos/asf/james-project/blob/0678047b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
index bace5d9..bf9de1b 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
@@ -60,6 +60,7 @@ import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.exception.AttachmentNotFoundException;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extractor.TextExtractor;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.mailbox.mock.MockMailboxSession;
 import org.apache.james.mailbox.model.AttachmentId;
@@ -117,9 +118,10 @@ public class SetMessagesCreationProcessorTest {
     @Before
     public void setUp() throws MailboxException {
         MessagePreviewGenerator messagePreview = mock(MessagePreviewGenerator.class);
+        TextExtractor textExtractor = mock(TextExtractor.class);
         MessageContentExtractor messageContentExtractor = new MessageContentExtractor();
         when(messagePreview.forTextBody(any())).thenReturn("text preview");
-        messageFactory = new MessageFactory(messagePreview, messageContentExtractor);
+        messageFactory = new MessageFactory(messagePreview, messageContentExtractor, textExtractor);
         mockedMailSpool = mock(MailSpool.class);
         mockedMailFactory = mock(MailFactory.class);
         mockedAttachmentManager = mock(AttachmentManager.class);

http://git-wip-us.apache.org/repos/asf/james-project/blob/0678047b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
index c0bd1f3..026d62b 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
@@ -20,11 +20,13 @@ package org.apache.james.jmap.model;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
+import static org.hamcrest.CoreMatchers.is;
 
 import java.io.ByteArrayInputStream;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
 import java.util.Date;
+import java.util.Optional;
 
 import javax.mail.Flags;
 import javax.mail.Flags.Flag;
@@ -34,7 +36,9 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.james.jmap.model.MessageFactory.MetaDataWithContent;
 import org.apache.james.jmap.utils.HtmlTextExtractor;
 import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.extractor.TextExtractor;
 import org.apache.james.mailbox.inmemory.InMemoryId;
+import org.apache.james.mailbox.inmemory.JsoupTextExtractor;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.Cid;
 import org.apache.james.mailbox.model.MessageAttachment;
@@ -59,9 +63,12 @@ public class MessageFactoryTest {
     @Before
     public void setUp() {
         htmlTextExtractor = mock(HtmlTextExtractor.class);
+        TextExtractor textExtractor = new JsoupTextExtractor();
+
         messagePreview = new MessagePreviewGenerator(htmlTextExtractor);
         MessageContentExtractor messageContentExtractor = new MessageContentExtractor();
-        messageFactory = new MessageFactory(messagePreview, messageContentExtractor);
+
+        messageFactory = new MessageFactory(messagePreview, messageContentExtractor, textExtractor);
     }
     @Test
     public void emptyMailShouldBeLoadedIntoMessage() throws Exception {
@@ -161,6 +168,7 @@ public class MessageFactoryTest {
                 .size(headers.length())
                 .preview("(Empty)")
                 .textBody("")
+                .htmlBody("")
                 .build();
         assertThat(testee).isEqualToComparingFieldByField(expected);
     }
@@ -314,4 +322,47 @@ public class MessageFactoryTest {
             .containsExactly("(Empty)", 1010L, "", ImmutableMap.of("Date", "Tue, 14 Jul 2015 12:30:42 +0000", "MIME-Version", "1.0"), ZONED_DATE);
     }
 
+    @Test
+    public void textBodyShouldBeSetIntoMessageInCaseOfHtmlBody() throws Exception {
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("CContent-Type: text/html\r\n"
+            + "Subject: message 1 subject\r\n"
+            + "\r\n"
+            + "my <b>HTML</b> message").getBytes(Charsets.UTF_8));
+        MetaDataWithContent testMail = MetaDataWithContent.builder()
+            .uid(MessageUid.of(2))
+            .flags(new Flags(Flag.SEEN))
+            .size(messageContent.read())
+            .internalDate(INTERNAL_DATE)
+            .content(messageContent)
+            .attachments(ImmutableList.of())
+            .mailboxId(MAILBOX_ID)
+            .messageId(TestMessageId.of(2))
+            .build();
+        Message testee = messageFactory.fromMetaDataWithContent(testMail);
+
+        assertThat(testee.getPreview()).isEqualTo("my HTML message");
+        assertThat(testee.getTextBody()).hasValue("my HTML message");
+        assertThat(testee.getHtmlBody()).hasValue("my <b>HTML</b> message");
+    }
+
+    @Test
+    public void textBodyShouldBeEmptyInCaseOfEmptyHtmlBodyAndEmptyTextBody() throws Exception {
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("CContent-Type: text/html\r\n"
+            + "Subject: message 1 subject\r\n").getBytes(Charsets.UTF_8));
+        MetaDataWithContent testMail = MetaDataWithContent.builder()
+            .uid(MessageUid.of(2))
+            .flags(new Flags(Flag.SEEN))
+            .size(messageContent.read())
+            .internalDate(INTERNAL_DATE)
+            .content(messageContent)
+            .attachments(ImmutableList.of())
+            .mailboxId(MAILBOX_ID)
+            .messageId(TestMessageId.of(2))
+            .build();
+        Message testee = messageFactory.fromMetaDataWithContent(testMail);
+
+        assertThat(testee.getPreview()).isEqualTo(MessagePreviewGenerator.NO_BODY);
+        assertThat(testee.getHtmlBody()).hasValue("");
+        assertThat(testee.getTextBody()).hasValue("");
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/0678047b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
index be8cda9..add4e29 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
@@ -38,6 +38,7 @@ import org.apache.james.jmap.model.MessagePreviewGenerator;
 import org.apache.james.mailbox.FlagsBuilder;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extractor.TextExtractor;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.mailbox.model.TestMessageId;
 import org.apache.mailet.Mail;
@@ -77,10 +78,11 @@ public class MailFactoryTest {
                 .messageId(TestMessageId.of(2))
                 .build();
         MessagePreviewGenerator messagePreview = mock(MessagePreviewGenerator.class);
+        TextExtractor textExtractor = mock(TextExtractor.class);
         when(messagePreview.forTextBody(any())).thenReturn("text preview");
 
         MessageContentExtractor messageContentExtractor = new MessageContentExtractor();
-        MessageFactory messageFactory = new MessageFactory(messagePreview, messageContentExtractor);
+        MessageFactory messageFactory = new MessageFactory(messagePreview, messageContentExtractor, textExtractor);
         jmapMessage = messageFactory.fromMetaDataWithContent(message);
     }
 


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


[5/6] james-project git commit: JAMES-1950 Add operations per minute curves to count graphics

Posted by bt...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/844b9519/grafana-reporting/SMTP count  board-1488774761350.json
----------------------------------------------------------------------
diff --git a/grafana-reporting/SMTP count  board-1488774761350.json b/grafana-reporting/SMTP count  board-1488774761350.json
index 23c7d51..3237734 100644
--- a/grafana-reporting/SMTP count  board-1488774761350.json	
+++ b/grafana-reporting/SMTP count  board-1488774761350.json	
@@ -1,8 +1,8 @@
 {
   "__inputs": [
     {
-      "name": "DS_ELASTICSEARCH",
-      "label": "ElasticSearch",
+      "name": "DS_JAMES_ES",
+      "label": "james es",
       "description": "",
       "type": "datasource",
       "pluginId": "elasticsearch",
@@ -42,22 +42,22 @@
   "rows": [
     {
       "collapse": false,
-      "height": 258,
+      "height": 263,
       "panels": [
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
           "id": 8,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -105,7 +105,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "SMPT Connections",
+          "title": "SMTP Connections",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -140,17 +140,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
           "id": 7,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -160,7 +160,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 6,
           "stack": false,
           "steppedLine": false,
@@ -171,7 +176,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -187,6 +192,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:SMTP-ehlo",
@@ -220,11 +233,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -239,22 +252,22 @@
     },
     {
       "collapse": false,
-      "height": 271,
+      "height": 250,
       "panels": [
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 10,
+          "id": 13,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -264,7 +277,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 6,
           "stack": false,
           "steppedLine": false,
@@ -275,7 +293,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -291,9 +309,17 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
-              "query": "name:SMTP-quit",
+              "query": "name:SMTP-DATA",
               "refId": "A",
               "timeField": "@timestamp"
             }
@@ -301,7 +327,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "SMTP-quit",
+          "title": "SMTP-data",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -324,11 +350,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -336,17 +362,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 11,
+          "id": 12,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -356,7 +382,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 6,
           "stack": false,
           "steppedLine": false,
@@ -367,7 +398,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -383,9 +414,17 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
-              "query": "name:SMTP-DATA",
+              "query": "name:SMTP-quit",
               "refId": "A",
               "timeField": "@timestamp"
             }
@@ -393,7 +432,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "SMTP-data",
+          "title": "SMTP-quit",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -416,11 +455,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -435,22 +474,22 @@
     },
     {
       "collapse": false,
-      "height": 308,
+      "height": 257,
       "panels": [
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 2,
+          "id": 14,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -460,7 +499,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 6,
           "stack": false,
           "steppedLine": false,
@@ -471,7 +515,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -487,6 +531,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:SMTP-rcpt",
@@ -520,11 +572,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -532,17 +584,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 6,
+          "id": 15,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -552,7 +604,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 6,
           "stack": false,
           "steppedLine": false,
@@ -563,7 +620,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -579,6 +636,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:SMTP-mail",
@@ -612,11 +677,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -667,5 +732,5 @@
   },
   "timezone": "browser",
   "title": "SMTP count  board",
-  "version": 6
+  "version": 3
 }
\ No newline at end of file


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


[4/6] james-project git commit: JAMES-1965 Simplify MessageFactory

Posted by bt...@apache.org.
JAMES-1965 Simplify MessageFactory


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

Branch: refs/heads/master
Commit: a52071339affde909dd6f193eee972c96ccc58c2
Parents: 030ed62
Author: Quynh Nguyen <qn...@linagora.com>
Authored: Tue Mar 21 15:07:12 2017 +0700
Committer: Quynh Nguyen <qn...@linagora.com>
Committed: Thu Mar 23 16:03:18 2017 +0700

----------------------------------------------------------------------
 .../apache/james/jmap/model/MessageFactory.java |  50 ++---
 .../jmap/model/MessagePreviewGenerator.java     |  32 +---
 .../jmap/methods/GetMessagesMethodTest.java     |  17 +-
 .../SetMessagesCreationProcessorTest.java       |   7 +-
 .../james/jmap/model/MessageFactoryTest.java    | 182 ++++++++++++++++++-
 .../jmap/model/MessagePreviewGeneratorTest.java | 155 ++--------------
 .../apache/james/jmap/send/MailFactoryTest.java |   7 +-
 7 files changed, 224 insertions(+), 226 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/a5207133/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 b49e3dc..53c9d7f 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
@@ -18,7 +18,6 @@
  ****************************************************************/
 package org.apache.james.jmap.model;
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.time.ZoneId;
@@ -39,9 +38,9 @@ import javax.mail.Flags;
 import javax.mail.internet.SharedInputStream;
 
 import org.apache.james.jmap.model.MessageContentExtractor.MessageContent;
+import org.apache.james.jmap.utils.HtmlTextExtractor;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.exception.MailboxException;
-import org.apache.james.mailbox.extractor.TextExtractor;
 import org.apache.james.mailbox.model.Cid;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageAttachment;
@@ -68,26 +67,24 @@ public class MessageFactory {
 
     private static final ZoneId UTC_ZONE_ID = ZoneId.of("Z");
 
-    private static final String HTML_CONTENT = "text/html";
-
-    private static final String EMPTY_FILE_NAME = "";
-
     private final MessagePreviewGenerator messagePreview;
     private final MessageContentExtractor messageContentExtractor;
-    private final TextExtractor textExtractor;
+    private final HtmlTextExtractor htmlTextExtractor;
 
     @Inject
-    public MessageFactory(MessagePreviewGenerator messagePreview, MessageContentExtractor messageContentExtractor, TextExtractor textExtractor) {
+    public MessageFactory(MessagePreviewGenerator messagePreview, MessageContentExtractor messageContentExtractor, HtmlTextExtractor htmlTextExtractor) {
         this.messagePreview = messagePreview;
         this.messageContentExtractor = messageContentExtractor;
-        this.textExtractor = textExtractor;
+        this.htmlTextExtractor = htmlTextExtractor;
     }
 
     public Message fromMetaDataWithContent(MetaDataWithContent message) throws MailboxException {
         org.apache.james.mime4j.dom.Message mimeMessage = parse(message);
         MessageContent messageContent = extractContent(mimeMessage);
         Optional<String> htmlBody = messageContent.getHtmlBody();
-        Optional<String> textBody = textBodyAndComputeFromHtmlBodyIfNeeded(htmlBody, messageContent.getTextBody());
+        Optional<String> mainTextContent = mainTextContent(messageContent);
+        Optional<String> textBody = computeTextBodyIfNeeded(messageContent, mainTextContent);
+        String preview = messagePreview.compute(mainTextContent);
         return Message.builder()
                 .id(message.getMessageId())
                 .blobId(BlobId.of(String.valueOf(message.getUid().asLong())))
@@ -109,23 +106,23 @@ public class MessageFactory {
                 .date(message.getInternalDateAsZonedDateTime())
                 .textBody(textBody)
                 .htmlBody(htmlBody)
-                .preview(getPreview(messageContent, textBody))
+                .preview(preview)
                 .attachments(getAttachments(message.getAttachments()))
                 .build();
     }
 
-    private Optional<String> textBodyAndComputeFromHtmlBodyIfNeeded(Optional<String> htmlBody, Optional<String> textBody) {
-        if (textBody.isPresent()) {
-            return textBody;
-        }
-        if (!htmlBody.isPresent()) {
-            return Optional.empty();
-        }
-        try {
-            return Optional.of(textExtractor.extractContent(new ByteArrayInputStream(htmlBody.get().getBytes()), HTML_CONTENT, EMPTY_FILE_NAME).getTextualContent());
-        } catch (Exception e) {
-            return Optional.empty();
-        }
+    private Optional<String> computeTextBodyIfNeeded(MessageContent messageContent, Optional<String> mainTextContent) {
+        return messageContent.getTextBody()
+            .map(Optional::of)
+            .orElse(mainTextContent);
+    }
+
+    private Optional<String> mainTextContent(MessageContent messageContent) {
+        return messageContent.getHtmlBody()
+            .map(htmlTextExtractor::toPlainText)
+            .filter(s -> !Strings.isNullOrEmpty(s))
+            .map(Optional::of)
+            .orElse(messageContent.getTextBody());
     }
 
     private org.apache.james.mime4j.dom.Message parse(MetaDataWithContent message) throws MailboxException {
@@ -149,13 +146,6 @@ public class MessageFactory {
         }
     }
 
-    private String getPreview(MessageContent messageContent, Optional<String> computedTextBody) {
-        if (messageContent.getHtmlBody().isPresent() && messageContent.getTextBody().isPresent()) {
-            return messagePreview.forHTMLBody(messageContent.getHtmlBody());
-        }
-        return messagePreview.forTextBody(computedTextBody);
-    }
-
     private Emailer firstFromMailboxList(MailboxList list) {
         if (list == null) {
             return null;

http://git-wip-us.apache.org/repos/asf/james-project/blob/a5207133/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessagePreviewGenerator.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessagePreviewGenerator.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessagePreviewGenerator.java
index 5a162cd..b5a15ea 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessagePreviewGenerator.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessagePreviewGenerator.java
@@ -21,46 +21,20 @@ package org.apache.james.jmap.model;
 
 import java.util.Optional;
 
-import javax.inject.Inject;
-
 import org.apache.commons.lang3.StringUtils;
-import org.apache.james.jmap.utils.HtmlTextExtractor;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
 
 public class MessagePreviewGenerator {
     
     public static final String NO_BODY = "(Empty)";
     public static final int MAX_PREVIEW_LENGTH = 256;
 
-    private final HtmlTextExtractor htmlTextExtractor;
-
-    @Inject
-    public MessagePreviewGenerator(HtmlTextExtractor htmlTextExtractor) {
-        this.htmlTextExtractor = htmlTextExtractor;
-    }
-
-    public String forHTMLBody(Optional<String> body) {
-        return body.filter(text -> !text.isEmpty())
-                .map(this::asText)
-                .map(this::abbreviate)
-                .orElse(NO_BODY);
-    }
-
-    public String forTextBody(Optional<String> body) {
-        return body.filter(text -> !text.isEmpty())
+    public String compute(Optional<String> textBody) {
+        return textBody.filter(text -> !text.isEmpty())
                 .map(this::abbreviate)
                 .orElse(NO_BODY);
     }
 
-    @VisibleForTesting String asText(String body) throws IllegalArgumentException {
-       Preconditions.checkArgument(body != null);
-       return htmlTextExtractor.toPlainText(body);
-    }
-
-    @VisibleForTesting String abbreviate(String body) {
+    private String abbreviate(String body) {
         return StringUtils.abbreviate(body, MAX_PREVIEW_LENGTH);
     }
-
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/a5207133/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
index 4686c3a..15873ee 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
@@ -20,9 +20,7 @@ package org.apache.james.jmap.methods;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import java.io.ByteArrayInputStream;
 import java.util.Date;
@@ -43,20 +41,21 @@ import org.apache.james.jmap.model.MessageContentExtractor;
 import org.apache.james.jmap.model.MessageFactory;
 import org.apache.james.jmap.model.MessagePreviewGenerator;
 import org.apache.james.jmap.model.MessageProperties.MessageProperty;
+import org.apache.james.jmap.utils.HtmlTextExtractor;
+import org.apache.james.jmap.utils.MailboxBasedHtmlTextExtractor;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageIdManager;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.acl.GroupMembershipResolver;
 import org.apache.james.mailbox.exception.MailboxException;
-import org.apache.james.mailbox.extractor.TextExtractor;
 import org.apache.james.mailbox.inmemory.InMemoryMessageIdManager;
-import org.apache.james.mailbox.inmemory.JsoupTextExtractor;
 import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
 import org.apache.james.mailbox.mock.MockMailboxSession;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.tika.extractor.TikaTextExtractor;
 import org.apache.james.metrics.logger.DefaultMetricFactory;
 import org.assertj.core.api.Condition;
 import org.assertj.core.data.MapEntry;
@@ -117,12 +116,10 @@ public class GetMessagesMethodTest {
     @Before
     public void setup() throws Exception {
         clientId = ClientId.of("#0");
-        MessagePreviewGenerator messagePreview = mock(MessagePreviewGenerator.class);
-        when(messagePreview.forHTMLBody(any())).thenReturn("html preview");
-        when(messagePreview.forTextBody(any())).thenReturn("text preview");
+        HtmlTextExtractor htmlTextExtractor = new MailboxBasedHtmlTextExtractor(new TikaTextExtractor());
+        MessagePreviewGenerator messagePreview = new MessagePreviewGenerator();
         MessageContentExtractor messageContentExtractor = new MessageContentExtractor();
-        TextExtractor textExtractor = new JsoupTextExtractor();
-        MessageFactory messageFactory = new MessageFactory(messagePreview, messageContentExtractor, textExtractor);
+        MessageFactory messageFactory = new MessageFactory(messagePreview, messageContentExtractor, htmlTextExtractor);
         InMemoryIntegrationResources inMemoryIntegrationResources = new InMemoryIntegrationResources();
         GroupMembershipResolver groupMembershipResolver = inMemoryIntegrationResources.createGroupMembershipResolver();
         mailboxManager = inMemoryIntegrationResources.createMailboxManager(groupMembershipResolver);
@@ -248,7 +245,6 @@ public class GetMessagesMethodTest {
                 .build();
 
         Stream<JmapResponse> result = testee.process(request, clientId, session);
-
         assertThat(result).hasSize(1)
             .extracting(JmapResponse::getProperties)
             .flatExtracting(Optional::get)
@@ -271,7 +267,6 @@ public class GetMessagesMethodTest {
         Set<MessageProperty> expected = Sets.newHashSet(MessageProperty.id, MessageProperty.subject);
 
         List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList());
-
         assertThat(result).hasSize(1)
             .extracting(JmapResponse::getProperties)
             .flatExtracting(Optional::get)

http://git-wip-us.apache.org/repos/asf/james-project/blob/a5207133/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
index bf9de1b..3d06a3b 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/SetMessagesCreationProcessorTest.java
@@ -53,6 +53,7 @@ import org.apache.james.jmap.model.mailbox.Role;
 import org.apache.james.jmap.send.MailFactory;
 import org.apache.james.jmap.send.MailMetadata;
 import org.apache.james.jmap.send.MailSpool;
+import org.apache.james.jmap.utils.HtmlTextExtractor;
 import org.apache.james.jmap.utils.SystemMailboxesProvider;
 import org.apache.james.mailbox.AttachmentManager;
 import org.apache.james.mailbox.MailboxSession;
@@ -117,11 +118,11 @@ public class SetMessagesCreationProcessorTest {
 
     @Before
     public void setUp() throws MailboxException {
+        HtmlTextExtractor htmlTextExtractor = mock(HtmlTextExtractor.class);
         MessagePreviewGenerator messagePreview = mock(MessagePreviewGenerator.class);
-        TextExtractor textExtractor = mock(TextExtractor.class);
         MessageContentExtractor messageContentExtractor = new MessageContentExtractor();
-        when(messagePreview.forTextBody(any())).thenReturn("text preview");
-        messageFactory = new MessageFactory(messagePreview, messageContentExtractor, textExtractor);
+        when(messagePreview.compute(any())).thenReturn("text preview");
+        messageFactory = new MessageFactory(messagePreview, messageContentExtractor, htmlTextExtractor);
         mockedMailSpool = mock(MailSpool.class);
         mockedMailFactory = mock(MailFactory.class);
         mockedAttachmentManager = mock(AttachmentManager.class);

http://git-wip-us.apache.org/repos/asf/james-project/blob/a5207133/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
index 74dad6f..1e0130c 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
@@ -19,8 +19,6 @@
 package org.apache.james.jmap.model;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.hamcrest.CoreMatchers.is;
 
 import java.io.ByteArrayInputStream;
 import java.time.ZoneId;
@@ -35,14 +33,14 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.james.jmap.model.MessageFactory.MetaDataWithContent;
 import org.apache.james.jmap.utils.HtmlTextExtractor;
+import org.apache.james.jmap.utils.MailboxBasedHtmlTextExtractor;
 import org.apache.james.mailbox.MessageUid;
-import org.apache.james.mailbox.extractor.TextExtractor;
 import org.apache.james.mailbox.inmemory.InMemoryId;
-import org.apache.james.mailbox.inmemory.JsoupTextExtractor;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.Cid;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.mailbox.model.TestMessageId;
+import org.apache.james.mailbox.tika.extractor.TikaTextExtractor;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -62,13 +60,12 @@ public class MessageFactoryTest {
     
     @Before
     public void setUp() {
-        htmlTextExtractor = mock(HtmlTextExtractor.class);
-        TextExtractor textExtractor = new JsoupTextExtractor();
+        htmlTextExtractor = new MailboxBasedHtmlTextExtractor(new TikaTextExtractor());
 
-        messagePreview = new MessagePreviewGenerator(htmlTextExtractor);
+        messagePreview = new MessagePreviewGenerator();
         MessageContentExtractor messageContentExtractor = new MessageContentExtractor();
 
-        messageFactory = new MessageFactory(messagePreview, messageContentExtractor, textExtractor);
+        messageFactory = new MessageFactory(messagePreview, messageContentExtractor, htmlTextExtractor);
     }
     @Test
     public void emptyMailShouldBeLoadedIntoMessage() throws Exception {
@@ -193,6 +190,42 @@ public class MessageFactoryTest {
     }
 
     @Test
+    public void textBodyShouldNotOverrideWhenItIsThere() throws Exception {
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("Subject\n"
+            + "MIME-Version: 1.0\n"
+            + "Content-Type: multipart/alternative;\n"
+            + "\tboundary=\"----=_Part_370449_1340169331.1489506420401\"\n"
+            + "\n"
+            + "------=_Part_370449_1340169331.1489506420401\n"
+            + "Content-Type: text/plain; charset=UTF-8\n"
+            + "Content-Transfer-Encoding: 7bit\n"
+            + "\n"
+            + "My plain message\n"
+            + "------=_Part_370449_1340169331.1489506420401\n"
+            + "Content-Type: text/html; charset=UTF-8\n"
+            + "Content-Transfer-Encoding: 7bit\n"
+            + "\n"
+            + "<a>The </a> <strong>HTML</strong> message"
+        ).getBytes(Charsets.UTF_8));
+
+        MetaDataWithContent testMail = MetaDataWithContent.builder()
+            .uid(MessageUid.of(2))
+            .flags(new Flags(Flag.SEEN))
+            .internalDate(INTERNAL_DATE)
+            .size(1000)
+            .content(messageContent)
+            .attachments(ImmutableList.of())
+            .mailboxId(MAILBOX_ID)
+            .messageId(TestMessageId.of(2))
+            .build();
+        Message testee = messageFactory.fromMetaDataWithContent(testMail);
+
+        assertThat(testee.getTextBody())
+            .isPresent()
+            .isEqualTo(Optional.of("My plain message"));
+    }
+
+    @Test
     public void previewShouldBeLimitedTo256Length() throws Exception {
         String headers = "Subject: test subject\n";
         String body300 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
@@ -365,4 +398,137 @@ public class MessageFactoryTest {
         assertThat(testee.getHtmlBody()).contains("");
         assertThat(testee.getTextBody()).isEmpty();
     }
+
+    @Test
+    public void previewBodyShouldReturnTruncatedStringWithoutHtmlTagWhenHtmlBodyContainTags() throws Exception {
+        String body = "This is a <b>HTML</b> mail containing <u>underlined part</u>, <i>italic part</i> and <u><i>underlined AND italic part</i></u>9999999999"
+            + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
+            + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
+            + "000000000011111111112222222222333333333344444444445555555";
+        String expected = "This is a HTML mail containing underlined part, italic part and underlined AND italic part9999999999"
+            + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
+            + "00000000001111111111222222222233333333334444444444555...";
+
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("CContent-Type: text/html\r\n"
+            + "Subject: message 1 subject\r\n"
+            + "\r\n"
+            + body).getBytes(Charsets.UTF_8));
+
+        MetaDataWithContent testMail = MetaDataWithContent.builder()
+            .uid(MessageUid.of(2))
+            .flags(new Flags(Flag.SEEN))
+            .size(messageContent.read())
+            .internalDate(INTERNAL_DATE)
+            .content(messageContent)
+            .attachments(ImmutableList.of())
+            .mailboxId(MAILBOX_ID)
+            .messageId(TestMessageId.of(2))
+            .build();
+        Message testee = messageFactory.fromMetaDataWithContent(testMail);
+
+        assertThat(testee.getPreview()).isEqualTo(expected);
+    }
+
+    @Test
+    public void previewBodyShouldReturnTextBodyWhenNoHtmlBody() throws Exception {
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("CContent-Type: text/plain\r\n"
+            + "Subject: message 1 subject\r\n"
+            + "\r\n"
+            + "My plain text").getBytes(Charsets.UTF_8));
+
+        MetaDataWithContent testMail = MetaDataWithContent.builder()
+            .uid(MessageUid.of(2))
+            .flags(new Flags(Flag.SEEN))
+            .size(messageContent.read())
+            .internalDate(INTERNAL_DATE)
+            .content(messageContent)
+            .attachments(ImmutableList.of())
+            .mailboxId(MAILBOX_ID)
+            .messageId(TestMessageId.of(2))
+            .build();
+        Message testee = messageFactory.fromMetaDataWithContent(testMail);
+
+        assertThat(testee.getPreview()).isEqualTo("My plain text");
+    }
+
+    @Test
+    public void previewBodyShouldReturnStringEmptyWhenNoHtmlBodyAndNoTextBody() throws Exception {
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("Subject: message 1 subject\r\n").getBytes(Charsets.UTF_8));
+
+        MetaDataWithContent testMail = MetaDataWithContent.builder()
+            .uid(MessageUid.of(2))
+            .flags(new Flags(Flag.SEEN))
+            .size(messageContent.read())
+            .internalDate(INTERNAL_DATE)
+            .content(messageContent)
+            .attachments(ImmutableList.of())
+            .mailboxId(MAILBOX_ID)
+            .messageId(TestMessageId.of(2))
+            .build();
+        Message testee = messageFactory.fromMetaDataWithContent(testMail);
+
+        assertThat(testee)
+            .extracting(Message::getPreview, Message::getHtmlBody, Message::getTextBody)
+            .containsExactly(MessagePreviewGenerator.NO_BODY, Optional.empty(), Optional.of(""));
+    }
+
+    @Test
+    public void previewBodyShouldReturnStringEmptyWhenNoMeaningHtmlBodyAndNoTextBody() throws Exception {
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("CContent-Type: text/html\r\n"
+            + "Subject: message 1 subject\r\n"
+            + "\r\n"
+            + "<html><body></body></html>").getBytes(Charsets.UTF_8));
+
+        MetaDataWithContent testMail = MetaDataWithContent.builder()
+            .uid(MessageUid.of(2))
+            .flags(new Flags(Flag.SEEN))
+            .size(messageContent.read())
+            .internalDate(INTERNAL_DATE)
+            .content(messageContent)
+            .attachments(ImmutableList.of())
+            .mailboxId(MAILBOX_ID)
+            .messageId(TestMessageId.of(2))
+            .build();
+        Message testee = messageFactory.fromMetaDataWithContent(testMail);
+
+        assertThat(testee)
+            .extracting(Message::getPreview, Message::getHtmlBody, Message::getTextBody)
+            .containsExactly(MessagePreviewGenerator.NO_BODY, Optional.of("<html><body></body></html>"), Optional.empty());
+    }
+
+    @Test
+    public void previewBodyShouldReturnTextBodyWhenNoMeaningHtmlBodyAndTextBody() throws Exception {
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("Subject\n"
+            + "MIME-Version: 1.0\n"
+            + "Content-Type: multipart/alternative;\n"
+            + "\tboundary=\"----=_Part_370449_1340169331.1489506420401\"\n"
+            + "\n"
+            + "------=_Part_370449_1340169331.1489506420401\n"
+            + "Content-Type: text/plain; charset=UTF-8\n"
+            + "Content-Transfer-Encoding: 7bit\n"
+            + "\n"
+            + "My plain message\n"
+            + "------=_Part_370449_1340169331.1489506420401\n"
+            + "Content-Type: text/html; charset=UTF-8\n"
+            + "Content-Transfer-Encoding: 7bit\n"
+            + "\n"
+            + "<html></html>"
+        ).getBytes(Charsets.UTF_8));
+
+        MetaDataWithContent testMail = MetaDataWithContent.builder()
+            .uid(MessageUid.of(2))
+            .flags(new Flags(Flag.SEEN))
+            .size(messageContent.read())
+            .internalDate(INTERNAL_DATE)
+            .content(messageContent)
+            .attachments(ImmutableList.of())
+            .mailboxId(MAILBOX_ID)
+            .messageId(TestMessageId.of(2))
+            .build();
+        Message testee = messageFactory.fromMetaDataWithContent(testMail);
+
+        assertThat(testee)
+            .extracting(Message::getPreview, Message::getHtmlBody, Message::getTextBody)
+            .containsExactly("My plain message", Optional.of("<html></html>"), Optional.of("My plain message"));
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/a5207133/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePreviewGeneratorTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePreviewGeneratorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePreviewGeneratorTest.java
index f9ae3b3..7874117 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePreviewGeneratorTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessagePreviewGeneratorTest.java
@@ -20,168 +20,39 @@
 package org.apache.james.jmap.model;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import java.util.Optional;
 
-import org.apache.james.jmap.utils.HtmlTextExtractor;
+import org.apache.commons.lang3.StringUtils;
 import org.junit.Before;
 import org.junit.Test;
 
 public class MessagePreviewGeneratorTest {
     
     private MessagePreviewGenerator testee;
-    private HtmlTextExtractor htmlTextExtractor;
-    
+
     @Before
     public void setUp() {
-        htmlTextExtractor = mock(HtmlTextExtractor.class);
-        testee = new MessagePreviewGenerator(htmlTextExtractor);
+        testee = new MessagePreviewGenerator();
     }
 
     @Test
-    public void forHTMLBodyShouldReturnTruncatedStringWithoutHtmlTagWhenStringContainTagsAndIsLongerThan256Characters() {
-        //Given
-        String body = "This is a <b>HTML</b> mail containing <u>underlined part</u>, <i>italic part</i> and <u><i>underlined AND italic part</i></u>9999999999"
-                + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "000000000011111111112222222222333333333344444444445555555";
-        String bodyWithoutTags = "This is a HTML mail containing underlined part, italic part and underlined AND italic part9999999999"
-                + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "000000000011111111112222222222333333333344444444445555555";
-        String expected = "This is a HTML mail containing underlined part, italic part and underlined AND italic part9999999999"
-                + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "00000000001111111111222222222233333333334444444444555...";
-        //When
-        when(htmlTextExtractor.toPlainText(body))
-            .thenReturn(bodyWithoutTags);
-        String actual = testee.forHTMLBody(Optional.of(body));
-        //Then
-        assertThat(actual).isEqualTo(expected);
+    public void computeShouldReturnStringEmptyWhenEmptyTextBody() throws Exception {
+        assertThat(testee.compute(Optional.empty())).isEqualTo(MessagePreviewGenerator.NO_BODY);
     }
 
     @Test
-    public void forHTMLBodyShouldReturnStringContainingEmptyWhenEmptyString() {
-        //Given
-        String body = "" ;
-        String expected = "(Empty)" ;
-        //When
-        when(htmlTextExtractor.toPlainText(body))
-            .thenReturn(expected);
-        String actual = testee.forHTMLBody(Optional.of(body));
-        //Then
-        assertThat(actual).isEqualTo(expected);
+    public void computeShouldReturnStringEmptyWhenStringEmptyTextBody() throws Exception {
+        assertThat(testee.compute(Optional.of(""))).isEqualTo(MessagePreviewGenerator.NO_BODY);
     }
 
     @Test
-    public void forTextBodyShouldReturnTruncatedStringWhenStringContainTagsAndIsLongerThan256Characters() {
-        //Given
-        String body = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "This is a <b>HTML</b> mail containing <u>underlined part</u>, <i>italic part</i>88888888889999999999"
-                + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "000000000011111111112222222222333333333344444444445555555";
-        String expected = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "This is a <b>HTML</b> mail containing <u>underlined part</u>, <i>italic part</i>88888888889999999999"
-                + "00000000001111111111222222222233333333334444444444555...";
-        //When
-        String actual = testee.forTextBody(Optional.of(body));
-        //Then
-        assertThat(actual).isEqualTo(expected);
-    }
+    public void computeShouldReturnStringIsLimitedTo256Length() throws Exception {
+        String body = StringUtils.leftPad("a", 300, "b");
+        String expected = StringUtils.leftPad("b", MessagePreviewGenerator.MAX_PREVIEW_LENGTH - 3, "b") + "...";
 
-    @Test
-    public void forTextBodyShouldReturnStringContainingEmptyWhenEmptyString() {
-        //Given
-        String expected = "(Empty)" ;
-        //When
-        String actual = testee.forTextBody(Optional.empty());
-        //Then
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void asTextShouldReturnStringWithoutHtmlTag() {
-        //Given
-        String body = "This is a <b>HTML</b> mail";
-        String expected = "This is a HTML mail";
-        //When
-        when(htmlTextExtractor.toPlainText(body))
-            .thenReturn(expected);
-        String actual = testee.asText(body);
-        //Then
-        assertThat(actual).isEqualTo(expected);
+        assertThat(testee.compute(Optional.of(body)))
+            .hasSize(MessagePreviewGenerator.MAX_PREVIEW_LENGTH)
+            .isEqualTo(expected);
     }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void asTextShouldThrowWhenNullString () {
-        testee.asText(null);
-    }
-
-    @Test
-    public void asTextShouldReturnEmptyStringWhenEmptyString() {
-        //Given
-        String body = "";
-        String expected = "";
-        //When
-        when(htmlTextExtractor.toPlainText(body))
-            .thenReturn(expected);
-        String actual = testee.asText(body);
-        //Then
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void abbreviateShouldNotTruncateAbodyWith256Length() {
-        //Given
-        String body256 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "00000000001111111111222222222233333333334444444444555555";
-        //When
-        String actual = testee.abbreviate(body256);
-        //Then
-        assertThat(body256.length()).isEqualTo(256);
-        assertThat(actual).isEqualTo(body256);
-    }
-
-    @Test
-    public void abbreviateShouldTruncateAbodyWith257Length() {
-        //Given
-        String body257 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "000000000011111111112222222222333333333344444444445555555";
-        String expected = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
-                + "00000000001111111111222222222233333333334444444444555...";
-        //When
-        String actual = testee.abbreviate(body257);
-        //Then
-        assertThat(body257.length()).isEqualTo(257);
-        assertThat(expected.length()).isEqualTo(256);
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void abbreviateShouldReturnNullStringWhenNullString() {
-        //Given
-        String body = null;
-        String expected = null;
-        //When
-        String actual = testee.abbreviate(body);
-        //Then
-        assertThat(actual).isEqualTo(expected);
-    }
-
-    @Test
-    public void abbreviateShouldReturnEmptyStringWhenEmptyString() {
-        //Given
-        String body = "";
-        String expected = "";
-        //When
-        String actual = testee.abbreviate(body);
-        //Then
-        assertThat(actual).isEqualTo(expected);
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/a5207133/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
index add4e29..34e4c59 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailFactoryTest.java
@@ -35,6 +35,7 @@ import org.apache.james.jmap.model.MessageContentExtractor;
 import org.apache.james.jmap.model.MessageFactory;
 import org.apache.james.jmap.model.MessageFactory.MetaDataWithContent;
 import org.apache.james.jmap.model.MessagePreviewGenerator;
+import org.apache.james.jmap.utils.HtmlTextExtractor;
 import org.apache.james.mailbox.FlagsBuilder;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.exception.MailboxException;
@@ -78,11 +79,11 @@ public class MailFactoryTest {
                 .messageId(TestMessageId.of(2))
                 .build();
         MessagePreviewGenerator messagePreview = mock(MessagePreviewGenerator.class);
-        TextExtractor textExtractor = mock(TextExtractor.class);
-        when(messagePreview.forTextBody(any())).thenReturn("text preview");
+        HtmlTextExtractor htmlTextExtractor = mock(HtmlTextExtractor.class);
+        when(messagePreview.compute(any())).thenReturn("text preview");
 
         MessageContentExtractor messageContentExtractor = new MessageContentExtractor();
-        MessageFactory messageFactory = new MessageFactory(messagePreview, messageContentExtractor, textExtractor);
+        MessageFactory messageFactory = new MessageFactory(messagePreview, messageContentExtractor, htmlTextExtractor);
         jmapMessage = messageFactory.fromMetaDataWithContent(message);
     }
 


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


[2/6] james-project git commit: JAMES-1965 Make htmlBody and textBody should be Optional

Posted by bt...@apache.org.
JAMES-1965 Make htmlBody and textBody should be Optional


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

Branch: refs/heads/master
Commit: 030ed62af30ee659cdcd37d5690441f836f81cd1
Parents: 4b70df9
Author: Quynh Nguyen <qn...@linagora.com>
Authored: Fri Mar 17 10:55:53 2017 +0700
Committer: Quynh Nguyen <qn...@linagora.com>
Committed: Thu Mar 23 16:03:17 2017 +0700

----------------------------------------------------------------------
 .../org/apache/james/jmap/model/Message.java    | 10 ++++----
 .../jmap/model/MessageContentExtractor.java     | 20 +++++++++-------
 .../apache/james/jmap/model/MessageFactory.java | 25 ++++++++++----------
 .../org/apache/james/jmap/model/SubMessage.java | 10 ++++----
 .../james/jmap/json/ParsingWritingObjects.java  |  5 ++--
 .../jmap/methods/GetMessagesMethodTest.java     |  4 ++--
 .../jmap/model/MessageContentExtractorTest.java |  8 +++----
 .../james/jmap/model/MessageFactoryTest.java    |  8 +++----
 .../apache/james/jmap/model/MessageTest.java    |  4 ++--
 .../james/jmap/model/SubMailboxMessageTest.java | 12 ++++++----
 10 files changed, 58 insertions(+), 48 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/030ed62a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Message.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Message.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Message.java
index 4799b3f..9351460 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Message.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Message.java
@@ -71,8 +71,8 @@ public class Message {
         private ZonedDateTime date;
         private Long size;
         private String preview;
-        private String textBody;
-        private String htmlBody;
+        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;
 
@@ -190,12 +190,12 @@ public class Message {
             return this;
         }
 
-        public Builder textBody(String textBody) {
+        public Builder textBody(Optional<String> textBody) {
             this.textBody = textBody;
             return this;
         }
 
-        public Builder htmlBody(String htmlBody) {
+        public Builder htmlBody(Optional<String> htmlBody) {
             this.htmlBody = htmlBody;
             return this;
         }
@@ -225,7 +225,7 @@ public class Message {
             boolean hasAttachment = hasAttachment(attachments);
 
             return new Message(id, blobId, threadId, mailboxIds, Optional.ofNullable(inReplyToMessageId), isUnread, isFlagged, isAnswered, isDraft, hasAttachment, headers, Optional.ofNullable(from),
-                    to.build(), cc.build(), bcc.build(), replyTo.build(), subject, date, size, preview, Optional.ofNullable(textBody), Optional.ofNullable(htmlBody), attachments, attachedMessages);
+                    to.build(), cc.build(), bcc.build(), replyTo.build(), subject, date, size, preview, textBody, htmlBody, attachments, attachedMessages);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/030ed62a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageContentExtractor.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageContentExtractor.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageContentExtractor.java
index c27bc3e..d5b096d 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageContentExtractor.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageContentExtractor.java
@@ -22,6 +22,7 @@ package org.apache.james.jmap.model;
 import java.io.IOException;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
@@ -55,7 +56,7 @@ public class MessageContentExtractor {
     }
 
     private MessageContent parseTextBody(Entity entity, TextBody textBody) throws IOException {
-        String bodyContent = asString(textBody);
+        Optional<String> bodyContent = asString(textBody);
         if (TEXT_HTML.equals(entity.getMimeType())) {
             return MessageContent.ofHtmlOnly(bodyContent);
         }
@@ -89,8 +90,8 @@ public class MessageContentExtractor {
             .orElse(MessageContent.empty());
     }
 
-    private String asString(TextBody textBody) throws IOException {
-        return IOUtils.toString(textBody.getInputStream(), textBody.getMimeCharset());
+    private Optional<String> asString(TextBody textBody) throws IOException {
+        return Optional.ofNullable(IOUtils.toString(textBody.getInputStream(), textBody.getMimeCharset()));
     }
 
     private MessageContent retrieveHtmlAndPlainTextContent(Multipart multipart) throws IOException {
@@ -141,6 +142,9 @@ public class MessageContentExtractor {
     }
 
     private Optional<String> getFirstMatchingTextBody(Multipart multipart, String mimeType, Predicate<Entity> condition) {
+        Function<TextBody, Optional<String>> textBodyOptionalFunction = Throwing
+            .<TextBody, Optional<String>>function(textBody ->  asString(textBody)).sneakyThrow();
+
         return multipart.getBodyParts()
             .stream()
             .filter(part -> mimeType.equals(part.getMimeType()))
@@ -149,7 +153,7 @@ public class MessageContentExtractor {
             .filter(TextBody.class::isInstance)
             .map(TextBody.class::cast)
             .findFirst()
-            .map(Throwing.function(this::asString).sneakyThrow());
+            .flatMap(textBodyOptionalFunction);
     }
 
     private boolean isNotAttachment(Entity part) {
@@ -169,12 +173,12 @@ public class MessageContentExtractor {
             this.htmlBody = htmlBody;
         }
 
-        public static MessageContent ofTextOnly(String textBody) {
-            return new MessageContent(Optional.of(textBody), Optional.empty());
+        public static MessageContent ofTextOnly(Optional<String> textBody) {
+            return new MessageContent(textBody, Optional.empty());
         }
 
-        public static MessageContent ofHtmlOnly(String htmlBody) {
-            return new MessageContent(Optional.empty(), Optional.of(htmlBody));
+        public static MessageContent ofHtmlOnly(Optional<String> htmlBody) {
+            return new MessageContent(Optional.empty(), htmlBody);
         }
 
         public static MessageContent empty() {

http://git-wip-us.apache.org/repos/asf/james-project/blob/030ed62a/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 5d7b2fa..b49e3dc 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
@@ -72,8 +72,6 @@ public class MessageFactory {
 
     private static final String EMPTY_FILE_NAME = "";
 
-    private static final String NO_BODY = "";
-
     private final MessagePreviewGenerator messagePreview;
     private final MessageContentExtractor messageContentExtractor;
     private final TextExtractor textExtractor;
@@ -88,8 +86,8 @@ public class MessageFactory {
     public Message fromMetaDataWithContent(MetaDataWithContent message) throws MailboxException {
         org.apache.james.mime4j.dom.Message mimeMessage = parse(message);
         MessageContent messageContent = extractContent(mimeMessage);
-        String htmlBody = messageContent.getHtmlBody().orElse(NO_BODY);
-        String textBody = messageContent.getTextBody().orElseGet(() -> textBodyFromHtmlBody(htmlBody).orElse(NO_BODY));
+        Optional<String> htmlBody = messageContent.getHtmlBody();
+        Optional<String> textBody = textBodyAndComputeFromHtmlBodyIfNeeded(htmlBody, messageContent.getTextBody());
         return Message.builder()
                 .id(message.getMessageId())
                 .blobId(BlobId.of(String.valueOf(message.getUid().asLong())))
@@ -116,9 +114,15 @@ public class MessageFactory {
                 .build();
     }
 
-    private Optional<String> textBodyFromHtmlBody(String htmlBody) {
+    private Optional<String> textBodyAndComputeFromHtmlBodyIfNeeded(Optional<String> htmlBody, Optional<String> textBody) {
+        if (textBody.isPresent()) {
+            return textBody;
+        }
+        if (!htmlBody.isPresent()) {
+            return Optional.empty();
+        }
         try {
-            return Optional.of(textExtractor.extractContent(new ByteArrayInputStream(htmlBody.getBytes()), HTML_CONTENT, EMPTY_FILE_NAME).getTextualContent());
+            return Optional.of(textExtractor.extractContent(new ByteArrayInputStream(htmlBody.get().getBytes()), HTML_CONTENT, EMPTY_FILE_NAME).getTextualContent());
         } catch (Exception e) {
             return Optional.empty();
         }
@@ -145,14 +149,11 @@ public class MessageFactory {
         }
     }
 
-    private String getPreview(MessageContent messageContent, String computedTextBody) {
-        if (messageContent.getHtmlBody().isPresent()) {
-            if (!messageContent.getTextBody().isPresent()) {
-                return messagePreview.forTextBody(Optional.of(computedTextBody));
-            }
+    private String getPreview(MessageContent messageContent, Optional<String> computedTextBody) {
+        if (messageContent.getHtmlBody().isPresent() && messageContent.getTextBody().isPresent()) {
             return messagePreview.forHTMLBody(messageContent.getHtmlBody());
         }
-        return messagePreview.forTextBody(messageContent.getTextBody());
+        return messagePreview.forTextBody(computedTextBody);
     }
 
     private Emailer firstFromMailboxList(MailboxList list) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/030ed62a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SubMessage.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SubMessage.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SubMessage.java
index cbaf1cd..95be80a 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SubMessage.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SubMessage.java
@@ -49,8 +49,8 @@ public class SubMessage {
         private final ImmutableList.Builder<Emailer> replyTo;
         private String subject;
         private ZonedDateTime date;
-        private String textBody;
-        private String htmlBody;
+        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;
         
@@ -103,12 +103,12 @@ public class SubMessage {
             return this;
         }
 
-        public Builder textBody(String textBody) {
+        public Builder textBody(Optional<String> textBody) {
             this.textBody = textBody;
             return this;
         }
 
-        public Builder htmlBody(String htmlBody) {
+        public Builder htmlBody(Optional<String> htmlBody) {
             this.htmlBody = htmlBody;
             return this;
         }
@@ -131,7 +131,7 @@ public class SubMessage {
             ImmutableMap<BlobId, SubMessage> attachedMessages = this.attachedMessages.build();
             Preconditions.checkState(Message.areAttachedMessagesKeysInAttachments(attachments, attachedMessages), "'attachedMessages' keys must be in 'attachements'");
             return new SubMessage(headers, Optional.ofNullable(from), to.build(), cc.build(), bcc.build(),
-                    replyTo.build(), subject, date, Optional.ofNullable(textBody), Optional.ofNullable(htmlBody),
+                    replyTo.build(), subject, date, textBody, htmlBody,
                     attachments, attachedMessages
                     );
         }

http://git-wip-us.apache.org/repos/asf/james-project/blob/030ed62a/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjects.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjects.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjects.java
index 62a9de4..3814b86 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjects.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/json/ParsingWritingObjects.java
@@ -21,6 +21,7 @@ package org.apache.james.jmap.json;
 
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
+import java.util.Optional;
 
 import org.apache.james.jmap.model.BlobId;
 import org.apache.james.jmap.model.Emailer;
@@ -61,8 +62,8 @@ public interface ParsingWritingObjects {
         ZonedDateTime DATE = ZonedDateTime.parse("2014-10-30T14:12:00Z").withZoneSameLocal(ZoneId.of("GMT"));
         int SIZE = 1024;
         String PREVIEW = "myPreview";
-        String TEXT_BODY = "myTextBody";
-        String HTML_BODY = "<h1>myHtmlBody</h1>";
+        Optional<String> TEXT_BODY = Optional.of("myTextBody");
+        Optional<String> HTML_BODY = Optional.of("<h1>myHtmlBody</h1>");
     }
 
     Message MESSAGE = Message.builder()

http://git-wip-us.apache.org/repos/asf/james-project/blob/030ed62a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
index 0c231ba..4686c3a 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
@@ -328,7 +328,7 @@ public class GetMessagesMethodTest {
     }
 
     @Test
-    public void processShouldEmptyTextBodyAndHtmlBodyWhenThoseAreEmpty() throws MailboxException {
+    public void processShouldReturnEmptyTextBodyAndHtmlBodyWhenThoseAreEmpty() throws MailboxException {
         MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
         Date now = new Date();
         ByteArrayInputStream messageContent = new ByteArrayInputStream(("Content-Type: text/html\r\n"
@@ -348,7 +348,7 @@ public class GetMessagesMethodTest {
             .extracting(GetMessagesResponse.class::cast)
             .flatExtracting(GetMessagesResponse::list)
             .extracting(Message::getId, Message::getTextBody, Message::getHtmlBody)
-            .containsOnly(Tuple.tuple(message.getMessageId(), Optional.empty(), Optional.empty()));
+            .containsOnly(Tuple.tuple(message.getMessageId(), Optional.empty(), Optional.of("")));
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/james-project/blob/030ed62a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageContentExtractorTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageContentExtractorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageContentExtractorTest.java
index 84f78c4..0182e63 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageContentExtractorTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageContentExtractorTest.java
@@ -435,8 +435,8 @@ public class MessageContentExtractorTest {
 
     @Test
     public void mergeMessageContentShouldReturnMixWhenFirstTextOnlyAndSecondHtmlOnly() {
-        MessageContent messageContent1 = MessageContent.ofTextOnly(TEXT_CONTENT);
-        MessageContent messageContent2 = MessageContent.ofHtmlOnly(HTML_CONTENT);
+        MessageContent messageContent1 = MessageContent.ofTextOnly(Optional.of(TEXT_CONTENT));
+        MessageContent messageContent2 = MessageContent.ofHtmlOnly(Optional.of(HTML_CONTENT));
         MessageContent expected = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
 
         MessageContent actual = messageContent1.merge(messageContent2);
@@ -446,8 +446,8 @@ public class MessageContentExtractorTest {
 
     @Test
     public void mergeMessageContentShouldReturnMixWhenFirstHtmlOnlyAndSecondTextOnly() {
-        MessageContent messageContent1 = MessageContent.ofHtmlOnly(HTML_CONTENT);
-        MessageContent messageContent2 = MessageContent.ofTextOnly(TEXT_CONTENT);
+        MessageContent messageContent1 = MessageContent.ofHtmlOnly(Optional.of(HTML_CONTENT));
+        MessageContent messageContent2 = MessageContent.ofTextOnly(Optional.of(TEXT_CONTENT));
         MessageContent expected = new MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
 
         MessageContent actual = messageContent1.merge(messageContent2);

http://git-wip-us.apache.org/repos/asf/james-project/blob/030ed62a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
index 026d62b..74dad6f 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
@@ -167,8 +167,8 @@ public class MessageFactoryTest {
                 .date(ZONED_DATE)
                 .size(headers.length())
                 .preview("(Empty)")
-                .textBody("")
-                .htmlBody("")
+                .textBody(Optional.of(""))
+                .htmlBody(Optional.empty())
                 .build();
         assertThat(testee).isEqualToComparingFieldByField(expected);
     }
@@ -362,7 +362,7 @@ public class MessageFactoryTest {
         Message testee = messageFactory.fromMetaDataWithContent(testMail);
 
         assertThat(testee.getPreview()).isEqualTo(MessagePreviewGenerator.NO_BODY);
-        assertThat(testee.getHtmlBody()).hasValue("");
-        assertThat(testee.getTextBody()).hasValue("");
+        assertThat(testee.getHtmlBody()).contains("");
+        assertThat(testee.getTextBody()).isEmpty();
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/030ed62a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
index 3ecac4a..844396d 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
@@ -203,8 +203,8 @@ public class MessageTest {
             .date(currentDate)
             .size(123)
             .preview("preview")
-            .textBody("textBody")
-            .htmlBody("htmlBody")
+            .textBody(Optional.of("textBody"))
+            .htmlBody(Optional.of("htmlBody"))
             .attachments(attachments)
             .attachedMessages(attachedMessages)
             .build();

http://git-wip-us.apache.org/repos/asf/james-project/blob/030ed62a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SubMailboxMessageTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SubMailboxMessageTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SubMailboxMessageTest.java
index daa2a8a..7047638 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SubMailboxMessageTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SubMailboxMessageTest.java
@@ -29,6 +29,10 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
 public class SubMailboxMessageTest {
+
+    private static final Optional<String> DEFAULT_TEXT_BODY = Optional.of("textBody");
+    private static final Optional<String> DEFAULT_HTML_BODY = Optional.of("htmlBody");
+
     @Test(expected=IllegalStateException.class)
     public void buildShouldThrowWhenHeadersIsNull() {
         SubMessage.builder().build();
@@ -106,8 +110,8 @@ public class SubMailboxMessageTest {
                 replyTo,
                 "subject",
                 currentDate,
-                Optional.of("textBody"),
-                Optional.of("htmlBody"),
+                DEFAULT_TEXT_BODY,
+                DEFAULT_HTML_BODY,
                 attachments,
                 attachedMessages);
         SubMessage tested = SubMessage.builder()
@@ -119,8 +123,8 @@ public class SubMailboxMessageTest {
             .replyTo(replyTo)
             .subject("subject")
             .date(currentDate)
-            .textBody("textBody")
-            .htmlBody("htmlBody")
+            .textBody(DEFAULT_TEXT_BODY)
+            .htmlBody(DEFAULT_HTML_BODY)
             .attachments(attachments)
             .attachedMessages(attachedMessages)
             .build();


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


[6/6] james-project git commit: JAMES-1950 Add operations per minute curves to count graphics

Posted by bt...@apache.org.
JAMES-1950 Add operations per minute curves to count graphics


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

Branch: refs/heads/master
Commit: 844b9519cd27a2099b6e2c2c2f8cde8aafdbe320
Parents: a520713
Author: Raphael Ouazana <ra...@linagora.com>
Authored: Wed Mar 22 18:28:35 2017 +0100
Committer: benwa <bt...@linagora.com>
Committed: Thu Mar 23 16:11:19 2017 +0700

----------------------------------------------------------------------
 .../IMAP count board-1488774815587.json         | 614 +++++++++++++------
 .../JMAP count board-1488774795514.json         | 468 ++++++++++----
 grafana-reporting/MailQueue-1490071879988.json  |  72 ++-
 .../SMTP count  board-1488774761350.json        | 195 ++++--
 4 files changed, 945 insertions(+), 404 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/844b9519/grafana-reporting/IMAP count board-1488774815587.json
----------------------------------------------------------------------
diff --git a/grafana-reporting/IMAP count board-1488774815587.json b/grafana-reporting/IMAP count board-1488774815587.json
index afebe6d..9d08b18 100644
--- a/grafana-reporting/IMAP count board-1488774815587.json	
+++ b/grafana-reporting/IMAP count board-1488774815587.json	
@@ -1,8 +1,8 @@
 {
   "__inputs": [
     {
-      "name": "DS_ELASTICSEARCH",
-      "label": "ElasticSearch",
+      "name": "DS_JAMES_ES",
+      "label": "james es",
       "description": "",
       "type": "datasource",
       "pluginId": "elasticsearch",
@@ -47,7 +47,7 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
           "id": 8,
           "legend": {
@@ -140,17 +140,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
           "id": 7,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -160,7 +160,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -171,7 +176,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -187,6 +192,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-LOGIN",
@@ -197,7 +210,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "Login",
+          "title": "IMAP-LOGIN",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -220,11 +233,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -232,17 +245,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 2,
+          "id": 25,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -252,7 +265,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -263,7 +281,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -279,6 +297,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-CAPABILITY",
@@ -289,7 +315,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "Capability",
+          "title": "IMAP-CAPABILITY",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -312,11 +338,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -324,17 +350,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 6,
+          "id": 26,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -344,7 +370,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -355,7 +386,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -371,6 +402,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-AUTHENTICATE",
@@ -381,7 +420,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "Authenticate",
+          "title": "IMAP-AUTHENTICATE",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -404,11 +443,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -428,17 +467,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
           "id": 10,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -448,7 +487,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -459,7 +503,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -475,6 +519,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-SELECT",
@@ -485,7 +537,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "Select",
+          "title": "IMAP-SELECT",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -508,11 +560,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -520,17 +572,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 11,
+          "id": 27,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -540,7 +592,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -551,7 +608,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -567,6 +624,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-GETQUOTAROOT",
@@ -577,7 +642,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "GetQuotaRoot",
+          "title": "IMAP-GETQUOTAROOT",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -600,11 +665,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -612,17 +677,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 16,
+          "id": 28,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -632,7 +697,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -643,7 +713,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -659,6 +729,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-FETCH",
@@ -692,11 +770,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -704,17 +782,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 21,
+          "id": 29,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -724,7 +802,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -735,7 +818,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -751,6 +834,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-APPEND",
@@ -776,7 +867,7 @@
           },
           "yaxes": [
             {
-              "format": "ms",
+              "format": "none",
               "label": null,
               "logBase": 1,
               "max": null,
@@ -784,11 +875,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -808,17 +899,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
           "id": 13,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -828,7 +919,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -839,7 +935,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -855,6 +951,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-IDLE",
@@ -888,11 +992,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -900,17 +1004,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 14,
+          "id": 30,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -920,7 +1024,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -931,7 +1040,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -947,6 +1056,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-NOOP",
@@ -980,11 +1097,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -992,17 +1109,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 15,
+          "id": 31,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1012,7 +1129,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1023,7 +1145,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1039,6 +1161,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-STORE",
@@ -1072,11 +1202,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1084,17 +1214,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 20,
+          "id": 32,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1104,7 +1234,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1115,7 +1250,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1131,6 +1266,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-LSUB",
@@ -1164,11 +1307,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1188,17 +1331,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
           "id": 9,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1208,7 +1351,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1219,7 +1367,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1235,6 +1383,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-NAMESPACE",
@@ -1268,11 +1424,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1280,17 +1436,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 17,
+          "id": 33,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1300,7 +1456,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1311,7 +1472,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1327,6 +1488,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-CLOSE",
@@ -1360,11 +1529,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1372,17 +1541,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 18,
+          "id": 34,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1392,7 +1561,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1403,7 +1577,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1419,6 +1593,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-LOGOUT",
@@ -1444,7 +1626,7 @@
           },
           "yaxes": [
             {
-              "format": "ms",
+              "format": "none",
               "label": null,
               "logBase": 1,
               "max": null,
@@ -1452,11 +1634,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1464,17 +1646,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 19,
+          "id": 35,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1484,7 +1666,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1495,7 +1682,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1505,12 +1692,20 @@
               "dsType": "elasticsearch",
               "metrics": [
                 {
-                  "field": "p99",
+                  "field": "count",
                   "id": "1",
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-LIST",
@@ -1521,7 +1716,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "IMAP_LIST",
+          "title": "IMAP-LIST",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -1544,11 +1739,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1568,17 +1763,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
           "id": 22,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1588,7 +1783,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1599,7 +1799,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1615,9 +1815,17 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
-              "query": "name:IMAP_CREATE",
+              "query": "name:IMAP-CREATE",
               "refId": "A",
               "timeField": "@timestamp"
             }
@@ -1648,11 +1856,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1660,17 +1868,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 23,
+          "id": 36,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1680,7 +1888,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1691,7 +1904,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1707,6 +1920,14 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-COPY",
@@ -1740,11 +1961,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1752,17 +1973,17 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 24,
+          "id": 37,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1772,7 +1993,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1783,7 +2009,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1793,12 +2019,20 @@
               "dsType": "elasticsearch",
               "metrics": [
                 {
-                  "field": "p99",
+                  "field": "count",
                   "id": "1",
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:IMAP-MOVE",
@@ -1832,11 +2066,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1887,5 +2121,5 @@
   },
   "timezone": "browser",
   "title": "IMAP count board",
-  "version": 17
+  "version": 4
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/844b9519/grafana-reporting/JMAP count board-1488774795514.json
----------------------------------------------------------------------
diff --git a/grafana-reporting/JMAP count board-1488774795514.json b/grafana-reporting/JMAP count board-1488774795514.json
index 1849b89..059174b 100644
--- a/grafana-reporting/JMAP count board-1488774795514.json	
+++ b/grafana-reporting/JMAP count board-1488774795514.json	
@@ -1,8 +1,8 @@
 {
   "__inputs": [
     {
-      "name": "DS_ELASTICSEARCH",
-      "label": "ElasticSearch",
+      "name": "DS_JAMES_ES",
+      "label": "james es",
       "description": "",
       "type": "datasource",
       "pluginId": "elasticsearch",
@@ -42,22 +42,26 @@
   "rows": [
     {
       "collapse": false,
-      "height": 194,
+      "height": 178,
       "panels": [
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 23,
+          "id": 29,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -67,7 +71,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -78,7 +87,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -90,10 +99,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-request",
@@ -127,11 +145,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -139,17 +157,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 2,
+          "id": 30,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -159,7 +181,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -170,7 +197,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -182,10 +209,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-getMailboxes",
@@ -219,11 +255,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -231,17 +267,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 11,
+          "id": 28,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -251,7 +291,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -262,7 +307,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -274,10 +319,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-getMessageList",
@@ -311,11 +365,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -323,17 +377,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 21,
+          "id": 31,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -343,7 +401,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -354,7 +417,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -366,10 +429,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-getMessages",
@@ -403,11 +475,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -427,17 +499,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 7,
+          "id": 32,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -447,7 +523,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -458,7 +539,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -470,10 +551,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-setMessages",
@@ -507,11 +597,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -519,17 +609,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 20,
+          "id": 33,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -539,7 +633,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -550,7 +649,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -562,10 +661,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-setMailboxes",
@@ -599,11 +707,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -611,17 +719,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 9,
+          "id": 34,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -631,7 +743,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -642,7 +759,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -654,10 +771,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-getVacationResponse",
@@ -691,11 +817,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -703,17 +829,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 17,
+          "id": 35,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -723,7 +853,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -734,7 +869,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -746,10 +881,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-setVacationResponse",
@@ -783,11 +927,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -807,17 +951,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 22,
+          "id": 36,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -827,7 +975,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -838,7 +991,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -850,10 +1003,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-upload-post",
@@ -887,11 +1049,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -899,17 +1061,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 18,
+          "id": 11,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -919,7 +1085,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -930,7 +1101,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -942,10 +1113,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-download-post",
@@ -979,11 +1159,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -991,17 +1171,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 19,
+          "id": 37,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1011,7 +1195,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1022,7 +1211,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1034,10 +1223,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-download-get",
@@ -1071,11 +1269,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1083,17 +1281,21 @@
         {
           "aliasColors": {},
           "bars": false,
-          "datasource": "${DS_ELASTICSEARCH}",
+          "datasource": "${DS_JAMES_ES}",
           "fill": 1,
-          "id": 26,
+          "id": 38,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "alignAsTable": false,
+            "avg": true,
+            "current": true,
+            "hideEmpty": false,
+            "hideZero": false,
+            "max": true,
             "min": false,
+            "rightSide": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -1103,7 +1305,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -1114,7 +1321,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -1126,10 +1333,19 @@
                 {
                   "field": "count",
                   "id": "1",
+                  "inlineScript": null,
                   "meta": {},
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
               "query": "name:JMAP-authentication-post",
@@ -1163,11 +1379,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -1188,8 +1404,8 @@
     "list": []
   },
   "time": {
-    "from": "now/d",
-    "to": "now/d"
+    "from": "now-2d",
+    "to": "now"
   },
   "timepicker": {
     "refresh_intervals": [
@@ -1218,5 +1434,5 @@
   },
   "timezone": "browser",
   "title": "JMAP count board",
-  "version": 9
+  "version": 7
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/844b9519/grafana-reporting/MailQueue-1490071879988.json
----------------------------------------------------------------------
diff --git a/grafana-reporting/MailQueue-1490071879988.json b/grafana-reporting/MailQueue-1490071879988.json
index ade94ba..e7387e1 100644
--- a/grafana-reporting/MailQueue-1490071879988.json
+++ b/grafana-reporting/MailQueue-1490071879988.json
@@ -164,13 +164,13 @@
           "fill": 1,
           "id": 28,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -180,7 +180,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -191,7 +196,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -207,9 +212,17 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
-              "query": "name:\"enqueuedMails:spool\"",
+              "query": "name:\"enqueuedMail:spool\"",
               "refId": "A",
               "timeField": "@timestamp"
             }
@@ -217,7 +230,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "enqueueMailTime:spool",
+          "title": "enqueuedMail:spool",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -240,11 +253,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -586,13 +599,13 @@
           "fill": 1,
           "id": 32,
           "legend": {
-            "avg": false,
-            "current": false,
-            "max": false,
+            "avg": true,
+            "current": true,
+            "max": true,
             "min": false,
             "show": true,
             "total": false,
-            "values": false
+            "values": true
           },
           "lines": true,
           "linewidth": 1,
@@ -602,7 +615,12 @@
           "pointradius": 5,
           "points": false,
           "renderer": "flot",
-          "seriesOverrides": [],
+          "seriesOverrides": [
+            {
+              "alias": "Derivative Max count",
+              "yaxis": 2
+            }
+          ],
           "span": 3,
           "stack": false,
           "steppedLine": false,
@@ -613,7 +631,7 @@
                   "field": "@timestamp",
                   "id": "2",
                   "settings": {
-                    "interval": "auto",
+                    "interval": "1m",
                     "min_doc_count": 0,
                     "trimEdges": 0
                   },
@@ -629,9 +647,17 @@
                   "pipelineAgg": "3",
                   "settings": {},
                   "type": "max"
+                },
+                {
+                  "field": "1",
+                  "id": "3",
+                  "meta": {},
+                  "pipelineAgg": "1",
+                  "settings": {},
+                  "type": "derivative"
                 }
               ],
-              "query": "name:\"enqueuedMails:outgoing\"",
+              "query": "name:\"enqueuedMail:outgoing\"",
               "refId": "A",
               "timeField": "@timestamp"
             }
@@ -639,7 +665,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "enqueueMailTime:spool",
+          "title": "enqueuedMails:outgoing",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -662,11 +688,11 @@
               "show": true
             },
             {
-              "format": "short",
+              "format": "opm",
               "label": null,
               "logBase": 1,
               "max": null,
-              "min": null,
+              "min": "0",
               "show": true
             }
           ]
@@ -752,7 +778,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "enqueueMailTime:spool",
+          "title": "enqueueMailTime:outgoing",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -844,7 +870,7 @@
           "thresholds": [],
           "timeFrom": null,
           "timeShift": null,
-          "title": "mailQueueSize:spool",
+          "title": "mailQueueSize:outgoing",
           "tooltip": {
             "shared": true,
             "sort": 0,
@@ -1047,5 +1073,5 @@
   },
   "timezone": "browser",
   "title": "MailQueue",
-  "version": 13
+  "version": 21
 }
\ No newline at end of file


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


[3/6] james-project git commit: JAMES-1965 Add more testings for "Compute textBody when htmlBody is available"

Posted by bt...@apache.org.
JAMES-1965 Add more testings for "Compute textBody when htmlBody is available"


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

Branch: refs/heads/master
Commit: 4b70df973b518d0d739c47f749b76813ced4ad4d
Parents: 0678047
Author: Quynh Nguyen <qn...@linagora.com>
Authored: Wed Mar 15 11:16:34 2017 +0700
Committer: Quynh Nguyen <qn...@linagora.com>
Committed: Thu Mar 23 16:03:17 2017 +0700

----------------------------------------------------------------------
 .../integration/GetMessageListMethodTest.java   |  30 +++++-
 .../cucumber/GetMessagesMethodStepdefs.java     |   5 +
 .../test/resources/cucumber/GetMessages.feature |  10 +-
 .../resources/eml/noTextBodyButHtmlBody.eml     |  84 +++++++++++++++
 .../jmap/methods/GetMessagesMethodTest.java     | 103 +++++++++++++++++--
 5 files changed, 223 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/4b70df97/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
index bf49a2f..c455813 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/GetMessageListMethodTest.java
@@ -50,8 +50,8 @@ import org.apache.james.mailbox.store.mail.model.Mailbox;
 import org.apache.james.mailbox.store.probe.MailboxProbe;
 import org.apache.james.modules.MailboxProbeImpl;
 import org.apache.james.probe.DataProbe;
-import org.apache.james.utils.JmapGuiceProbe;
 import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.JmapGuiceProbe;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -1054,6 +1054,34 @@ public abstract class GetMessageListMethodTest {
             .body("[1][1].list[0].id", equalTo(message.getMessageId().serialize()));
     }
 
+    @Test
+    public void getMessageListShouldComputeTextBodyWhenNoTextBodyButHtmlBody() throws Exception {
+        mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox");
+
+        String mailContent = "Content-Type: text/html\r\n"
+            + "Subject: message 1 subject\r\n"
+            + "\r\n"
+            + "Hello <b>someone</b>, and thank you for joining example.com!";
+        LocalDate date = LocalDate.now();
+        mailboxProbe.appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"),
+            new ByteArrayInputStream(mailContent.getBytes()), convertToDate(date.plusDays(1)), false, new Flags());
+        await();
+
+        given()
+            .header("Authorization", accessToken.serialize())
+            .body("[[\"getMessageList\", {\"fetchMessages\": true, \"fetchMessageProperties\": [\"htmlBody\", \"textBody\"]}, \"#0\"]]")
+        .when()
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .body("[0][0]", equalTo("messageList"))
+            .body("[1][0]", equalTo("messages"))
+            .body("[0][1].messageIds", hasSize(1))
+            .body("[1][1].list[0].htmlBody", equalTo("Hello <b>someone</b>, and thank you for joining example.com!"))
+            .body("[1][1].list[0].textBody", equalTo("Hello someone, and thank you for joining example.com!"))
+        ;
+    }
+
     private Date convertToDate(LocalDate localDate) {
         return Date.from(localDate.atStartOfDay(ZONE_ID).toInstant());
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/4b70df97/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
index 23afc1d..070b219 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
@@ -203,6 +203,11 @@ public class GetMessagesMethodStepdefs {
         appendMessage(messageName, "eml/textInMainMultipartHtmlInInnerMultipart.eml");
     }
 
+    @Given("^the user has a message \"([^\"]*)\" in \"([^\"]*)\" mailbox with html body and no text body$")
+    public void appendMessageWithNoTextButHtml(String messageName, String mailbox) throws Throwable {
+        appendMessage(messageName, "eml/noTextBodyButHtmlBody.eml");
+    }
+
     private void appendMessage(String messageName, String emlFileName) throws Exception {
         ZonedDateTime dateTime = ZonedDateTime.parse("2014-10-30T14:12:00Z");
         MessageId id = mainStepdefs.jmapServer.getProbe(MailboxProbeImpl.class).appendMessage(userStepdefs.lastConnectedUser,

http://git-wip-us.apache.org/repos/asf/james-project/blob/4b70df97/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
index 3a72bf8..c8d1050 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
@@ -239,4 +239,12 @@ Feature: GetMessages method
     Then no error is returned
     And the list should contain 1 message
     And the textBody of the message is "/blabla/\r\n*bloblo*\r\n"
-    And the htmlBody of the message is "<i>blabla</i>\r\n<b>bloblo</b>\r\n"
\ No newline at end of file
+    And the htmlBody of the message is "<i>blabla</i>\r\n<b>bloblo</b>\r\n"
+
+  Scenario: Retrieving message should compute text body from html body
+    Given the user has a message "m1" in "INBOX" mailbox with html body and no text body
+    When the user ask for messages "m1"
+    Then no error is returned
+    And the list should contain 1 message
+    And the textBody of the message is "The Test User created an issue"
+    And the htmlBody of the message is "<a>The Test User</a> <strong>created</strong> an issue"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/4b70df97/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/noTextBodyButHtmlBody.eml
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/noTextBodyButHtmlBody.eml b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/noTextBodyButHtmlBody.eml
new file mode 100644
index 0000000..8a503c7
--- /dev/null
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/noTextBodyButHtmlBody.eml
@@ -0,0 +1,84 @@
+Return-Path: <returnPath>
+Received: from localhost (localhost [127.0.0.1])
+    by localhost (Postfix) with ESMTP id 27358B3A09;
+    Tue, 11 Oct 2016 11:59:12 +0200 (CEST)
+X-Sieve: CMU Sieve 2.2
+Date: Tue, 14 Mar 2017 16:47:05 +0100 (CET)
+From: "Test User (JIRA)" <te...@localhost>
+To: you@localhost
+Message-ID: <JI...@Atlassian.JIRA>
+In-Reply-To: <JI...@Atlassian.JIRA>
+References: <JI...@Atlassian.JIRA> <JI...@localhost>
+Subject: [JIRA] (CHAT-338) Update + icon
+MIME-Version: 1.0
+Content-Type: multipart/related;
+	boundary="----=_Part_370449_1340169331.1489506420401"
+X-JIRA-FingerPrint: 2cc56fe0b6c36a47776991d4aa5e9674
+Auto-Submitted: auto-generated
+Precedence: bulk
+
+------=_Part_370449_1340169331.1489506420401
+Content-Type: text/html; charset=UTF-8
+Content-Transfer-Encoding: 7bit
+
+<a>The Test User</a> <strong>created</strong> an issue
+------=_Part_370449_1340169331.1489506420401
+Content-Type: image/png
+Content-Transfer-Encoding: base64
+Content-Disposition: inline
+Content-ID: <jira-generated-image-static-major-2aab6bf2-4155-47c6-9c0b-b0ec1fdeaf9a>
+
+iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEX////QRDfQRDfQRDfQRDfQ
+RDcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACFHZsIAAAABXRSTlMAEZnM3Uchgx8AAAAb
+dEVYdGppcmEtc3lzdGVtLWltYWdlLXR5cGUAaWNvbroqOUUAAABESURBVHjaY2BAAsKGQIKJgYFR
+SUkAzBBSYFIEMRiVHvwDCjExMMk9+PdIgYGF4f+9D//v8YJ1sQZAdEEACuP/BwYSAQCDPg0vvqNM
+LwAAAABJRU5ErkJggu2YDBYHBhIBAEDzBgwy4Sb4AAAAAElFTkSuQmCC
+------=_Part_370449_1340169331.1489506420401
+Content-Type: image/png
+Content-Transfer-Encoding: base64
+Content-Disposition: inline
+Content-ID: <jira-generated-image-static-comment-icon-d374d5f6-0597-421c-a4ef-50f59dbc5d33>
+
+iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAADAFBMVEX///+1tbWzs7OysrKrq6um
+pqalpaWdnZ2ZmZn///+VlZWPj4/7+/vu7u7p6enn5+fl5eXk5OTh4eHW1tbT09PMzMzJycm6urq5
+ubm1tbWzs7OysrKrq6upqamlpaWKioqFhYWRkZGKioqHh4eDg4OAgIB/f398fHx6enp4eHh2dnZ0
+dHRycnJwcHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+gg==
+------=_Part_370449_1340169331.1489506420401
+Content-Type: image/png
+Content-Transfer-Encoding: base64
+Content-Disposition: inline
+Content-ID: <jira-generated-image-avatar-da8398c1-34c5-42a8-886f-d6628dead0f6>
+
+iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAHXRFWHRqaXJhLXN5c3RlbS1pbWFn
+ZS10eXBlAGF2YXRhcuQCGmEAAAdtSURBVHjaTdfFD5ZXEwXwZ0mBBHdoIbhT3Iq7tTgUh1KcFoq7
+Oy3W4pZAsA0JsIIFWxYECQk7Vvwf8+U3X27Txc19H7vnzJkzc+9b9evXL4YMGRLjx4+PoUOHxuDB
+g6Nt27bRqlWraNSoUbRu3TqfGT/88EPMmTMn3rx5E69fv44HDx7EzZs34+rVq3HlypX4+++/4+LF
+i3HhwoX8fe3atbhz507cv38/bt26FWvWrImRI0fGtGnTYvfu3XH58uWoXHz//ffRu3fv6Nq1a3Tr
+rkJggg==
+------=_Part_370449_1340169331.1489506420401
+Content-Type: image/png
+Content-Transfer-Encoding: base64
+Content-Disposition: inline
+Content-ID: <jira-generated-image-static-task-f154c5ed-6f31-40fe-9282-434de712f077>
+
+iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAADAFBMVEX///+1tbWzs7OwsLD////7
++/v5+fn6+Pbx7enm39jZ2dnW1tbT09PPz8+9qZiwmIOojninjXaLi4uliXKjh2+egWeBgYF7e3ty
+cnJwcHCIZEWGYkOFYECDXj2CXDyBXDuBWzoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AwO/ydzq3Plz9/gBVQQxEb0tW8YAAAAASUVORK5CYII=
+------=_Part_370449_1340169331.1489506420401
+Content-Type: image/png
+Content-Transfer-Encoding: base64
+Content-Disposition: inline
+Content-ID: <jira-generated-image-static-footer-desktop-logo-a08425e9-9554-4b52-8ae2-e2527647f29b>
+
+iVBORw0KGgoAAAANSUhEUgAAAKkAAAAkCAYAAADy+xopAAAAG3RFWHRqaXJhLXN5c3RlbS1pbWFn
+ZS10eXBlAGxvZ287MIqNAAAFV0lEQVR42u2cLbPrIBCGq1A4VFQUqg4VhUKh4qKizt89+U3ntjNk
+LpcB9oOkac9F7ExFwkd4uru8S3Lbvr/XYOZh4mG3C02EcexjunX73fbz8wPa88LlYV/BnmBMD5Mv
+HqwM/a7RWOa+iB3SHdKn93IRHLv5h+kTvesTzHuAMe17egOv3u2NIN1tTLzqV+LVpnCNbIByDO3M
+hX6e/Q998TqkJUh3M0nYLZkPNoV7Upuia6C2luC1+8J1SFGQ7imArnjWo2zucHZIuZDGpoJXPArY
+JbSn+iJ1OwrSNK/UUShfEUDuKYG+QDXo9sshHYOdOchX9NGi2d6TPPv+yyDJzU98EqSxdmoDTK0T
+nvfbckn7YgAAAABJRU5ErkJggg==
+------=_Part_370449_1340169331.1489506420401--

http://git-wip-us.apache.org/repos/asf/james-project/blob/4b70df97/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
index 45b6d76..0c231ba 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/GetMessagesMethodTest.java
@@ -49,7 +49,9 @@ import org.apache.james.mailbox.MessageIdManager;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.acl.GroupMembershipResolver;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extractor.TextExtractor;
 import org.apache.james.mailbox.inmemory.InMemoryMessageIdManager;
+import org.apache.james.mailbox.inmemory.JsoupTextExtractor;
 import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
 import org.apache.james.mailbox.mock.MockMailboxSession;
 import org.apache.james.mailbox.model.ComposedMessageId;
@@ -119,7 +121,8 @@ public class GetMessagesMethodTest {
         when(messagePreview.forHTMLBody(any())).thenReturn("html preview");
         when(messagePreview.forTextBody(any())).thenReturn("text preview");
         MessageContentExtractor messageContentExtractor = new MessageContentExtractor();
-        MessageFactory messageFactory = new MessageFactory(messagePreview, messageContentExtractor);
+        TextExtractor textExtractor = new JsoupTextExtractor();
+        MessageFactory messageFactory = new MessageFactory(messagePreview, messageContentExtractor, textExtractor);
         InMemoryIntegrationResources inMemoryIntegrationResources = new InMemoryIntegrationResources();
         GroupMembershipResolver groupMembershipResolver = inMemoryIntegrationResources.createGroupMembershipResolver();
         mailboxManager = inMemoryIntegrationResources.createMailboxManager(groupMembershipResolver);
@@ -182,9 +185,9 @@ public class GetMessagesMethodTest {
             .flatExtracting(GetMessagesResponse::list)
             .extracting(Message::getId, Message::getSubject, Message::getTextBody)
             .containsOnly(
-                    Tuple.tuple(message1.getMessageId(), "message 1 subject", Optional.of("my message")), 
-                    Tuple.tuple(message2.getMessageId(), "message 2 subject", Optional.of("my message")),
-                    Tuple.tuple(message3.getMessageId(), "", Optional.of("my message")));
+                Tuple.tuple(message1.getMessageId(), "message 1 subject", Optional.of("my message")),
+                Tuple.tuple(message2.getMessageId(), "message 2 subject", Optional.of("my message")),
+                Tuple.tuple(message3.getMessageId(), "", Optional.of("my message")));
     }
     
     @Test
@@ -208,8 +211,8 @@ public class GetMessagesMethodTest {
             .hasOnlyElementsOfType(GetMessagesResponse.class)
             .extracting(GetMessagesResponse.class::cast)
             .flatExtracting(GetMessagesResponse::list)
-            .extracting(Message::getId, Message::getTextBody, Message::getHtmlBody)
-            .containsOnly(Tuple.tuple(message.getMessageId(), Optional.empty(), Optional.of("my <b>HTML</b> message")));
+            .extracting(Message::getId, Message::getHtmlBody)
+            .containsOnly(Tuple.tuple(message.getMessageId(), Optional.of("my <b>HTML</b> message")));
     }
 
     @Test
@@ -298,7 +301,93 @@ public class GetMessagesMethodTest {
             .asList()
             .containsOnlyElementsOf(expected);
     }
-    
+
+    @Test
+    public void processShouldReturnTextBodyWhenEmptyTextBodyAndNotEmptyHtmlBody() throws MailboxException {
+        MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
+        Date now = new Date();
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("Content-Type: text/html\r\n"
+            + "Subject: message 1 subject\r\n"
+            + "\r\n"
+            + "my <b>HTML</b> message").getBytes(Charsets.UTF_8));
+        ComposedMessageId message = inbox.appendMessage(messageContent, now, session, false, null);
+
+        GetMessagesRequest request = GetMessagesRequest.builder()
+            .ids(ImmutableList.of(message.getMessageId()))
+            .build();
+
+        List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList());
+
+        assertThat(result).hasSize(1)
+            .extracting(JmapResponse::getResponse)
+            .hasOnlyElementsOfType(GetMessagesResponse.class)
+            .extracting(GetMessagesResponse.class::cast)
+            .flatExtracting(GetMessagesResponse::list)
+            .extracting(Message::getId, Message::getTextBody, Message::getHtmlBody)
+            .containsOnly(Tuple.tuple(message.getMessageId(), Optional.of("my HTML message"), Optional.of("my <b>HTML</b> message")));
+    }
+
+    @Test
+    public void processShouldEmptyTextBodyAndHtmlBodyWhenThoseAreEmpty() throws MailboxException {
+        MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
+        Date now = new Date();
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("Content-Type: text/html\r\n"
+            + "Subject: message 1 subject\r\n"
+            + "\r\n").getBytes(Charsets.UTF_8));
+        ComposedMessageId message = inbox.appendMessage(messageContent, now, session, false, null);
+
+        GetMessagesRequest request = GetMessagesRequest.builder()
+            .ids(ImmutableList.of(message.getMessageId()))
+            .build();
+
+        List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList());
+
+        assertThat(result).hasSize(1)
+            .extracting(JmapResponse::getResponse)
+            .hasOnlyElementsOfType(GetMessagesResponse.class)
+            .extracting(GetMessagesResponse.class::cast)
+            .flatExtracting(GetMessagesResponse::list)
+            .extracting(Message::getId, Message::getTextBody, Message::getHtmlBody)
+            .containsOnly(Tuple.tuple(message.getMessageId(), Optional.empty(), Optional.empty()));
+    }
+
+    @Test
+    public void processShouldNotOverrideTextBodyWhenItIsThere() throws MailboxException {
+        MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);
+        Date now = new Date();
+        ByteArrayInputStream messageContent = new ByteArrayInputStream(("Subject\n"
+            + "MIME-Version: 1.0\n"
+            + "Content-Type: multipart/alternative;\n"
+            + "\tboundary=\"----=_Part_370449_1340169331.1489506420401\"\n"
+            + "\n"
+            + "------=_Part_370449_1340169331.1489506420401\n"
+            + "Content-Type: text/plain; charset=UTF-8\n"
+            + "Content-Transfer-Encoding: 7bit\n"
+            + "\n"
+            + "My plain message\n"
+            + "------=_Part_370449_1340169331.1489506420401\n"
+            + "Content-Type: text/html; charset=UTF-8\n"
+            + "Content-Transfer-Encoding: 7bit\n"
+            + "\n"
+            + "<a>The </a> <strong>HTML</strong> message"
+        ).getBytes(Charsets.UTF_8));
+        ComposedMessageId message = inbox.appendMessage(messageContent, now, session, false, null);
+
+        GetMessagesRequest request = GetMessagesRequest.builder()
+            .ids(ImmutableList.of(message.getMessageId()))
+            .build();
+
+        List<JmapResponse> result = testee.process(request, clientId, session).collect(Collectors.toList());
+
+        assertThat(result).hasSize(1)
+            .extracting(JmapResponse::getResponse)
+            .hasOnlyElementsOfType(GetMessagesResponse.class)
+            .extracting(GetMessagesResponse.class::cast)
+            .flatExtracting(GetMessagesResponse::list)
+            .extracting(Message::getId, Message::getTextBody, Message::getHtmlBody)
+            .containsOnly(Tuple.tuple(message.getMessageId(), Optional.of("My plain message"), Optional.of("<a>The </a> <strong>HTML</strong> message")));
+    }
+
     @Test
     public void processShouldReturnHeadersFieldWhenSpecificHeadersRequestedInPropertyList() throws MailboxException {
         MessageManager inbox = mailboxManager.getMailbox(inboxPath, session);


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