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 2019/05/07 04:24:30 UTC

[james-project] 02/03: JAMES-2716 BigMessage MailboxListener implementation

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 969de070e8323c0c20240c2f751c6edb813c4e53
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Fri Apr 19 15:35:28 2019 +0700

    JAMES-2716 BigMessage MailboxListener implementation
---
 examples/custom-listeners/pom.xml                  |  49 +++++
 .../custom/listeners/BigMessageListener.java       | 112 ++++++++++++
 .../src/main/resources/listeners.xml               |  25 +++
 .../custom/listeners/BigMessageListenerTest.java   | 203 +++++++++++++++++++++
 examples/pom.xml                                   |   1 +
 5 files changed, 390 insertions(+)

diff --git a/examples/custom-listeners/pom.xml b/examples/custom-listeners/pom.xml
new file mode 100644
index 0000000..07be61d
--- /dev/null
+++ b/examples/custom-listeners/pom.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>examples</artifactId>
+        <groupId>org.apache.james</groupId>
+        <version>3.4.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>custom-listeners</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-api</artifactId>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/BigMessageListener.java b/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/BigMessageListener.java
new file mode 100644
index 0000000..14f27f1
--- /dev/null
+++ b/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/BigMessageListener.java
@@ -0,0 +1,112 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.examples.custom.listeners;
+
+import javax.inject.Inject;
+import javax.mail.Flags;
+
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageIdManager;
+import org.apache.james.mailbox.MessageManager.FlagsUpdateMode;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.events.Event;
+import org.apache.james.mailbox.events.Group;
+import org.apache.james.mailbox.events.MailboxListener;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.FetchGroupImpl;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.MessageResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A Listener to determine the size of added messages.
+ *
+ * If the size is greater or equals than the BIG_MESSAGE size threshold ({@value ONE_MB}).
+ * Then it will be considered as a big message and added BIG_MESSAGE {@value BIG_MESSAGE} flag
+ *
+ */
+class BigMessageListener implements MailboxListener.GroupMailboxListener {
+
+    public static class BigMessageListenerGroup extends Group {
+    }
+
+    private static final BigMessageListenerGroup GROUP = new BigMessageListenerGroup();
+    private static final Logger LOGGER = LoggerFactory.getLogger(BigMessageListener.class);
+
+    static final long ONE_MB = 1000L * 1000L;
+
+    static String BIG_MESSAGE = "BIG_MESSAGE";
+
+    private final MailboxManager mailboxManager;
+    private final MessageIdManager messageIdManager;
+
+    @Inject
+    BigMessageListener(MailboxManager mailboxManager, MessageIdManager messageIdManager) {
+        this.mailboxManager = mailboxManager;
+        this.messageIdManager = messageIdManager;
+    }
+
+    @Override
+    public void event(Event event) {
+        if (event instanceof MailboxListener.Added) {
+            MailboxListener.Added addedEvent = (MailboxListener.Added) event;
+            addedEvent.getUids().stream()
+                .filter(messageUid -> isBig(addedEvent, messageUid))
+                .forEach(messageUid -> setBigMessageFlag(addedEvent, messageUid));
+        }
+    }
+
+    private boolean isBig(Added addedEvent, MessageUid messageUid) {
+        return addedEvent.getMetaData(messageUid).getSize() >= ONE_MB;
+    }
+
+    private void setBigMessageFlag(Added addedEvent, MessageUid messageUid) {
+        try {
+            MailboxSession session = mailboxManager.createSystemSession(addedEvent.getUser().asString());
+            MessageId messageId = addedEvent.getMetaData(messageUid).getMessageId();
+
+            messageIdManager.getMessages(ImmutableList.of(messageId), FetchGroupImpl.MINIMAL, session)
+                .forEach(messageResult -> setBigMessageFlag(messageResult, session));
+        } catch (MailboxException e) {
+            LOGGER.error("error happens when adding '{}' flag to big messages from user {}",
+                BIG_MESSAGE, addedEvent.getUser().asString(), e);
+        }
+    }
+
+    private void setBigMessageFlag(MessageResult messageResult, MailboxSession session) {
+        try {
+            messageIdManager.setFlags(
+                new Flags(BIG_MESSAGE),
+                FlagsUpdateMode.ADD, messageResult.getMessageId(), ImmutableList.of(messageResult.getMailboxId()), session);
+        } catch (MailboxException e) {
+            LOGGER.error("error happens when adding '{}' flag to message {}",
+                BIG_MESSAGE, messageResult.getMessageId().serialize(), e);
+        }
+    }
+
+    @Override
+    public Group getDefaultGroup() {
+        return GROUP;
+    }
+}
diff --git a/examples/custom-listeners/src/main/resources/listeners.xml b/examples/custom-listeners/src/main/resources/listeners.xml
new file mode 100644
index 0000000..ebac3d6
--- /dev/null
+++ b/examples/custom-listeners/src/main/resources/listeners.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+ -->
+
+<listeners>
+  <listener>
+    <class>org.apache.james.examples.custom.listeners.BigMessageListener</class>
+  </listener>
+</listeners>
\ No newline at end of file
diff --git a/examples/custom-listeners/src/test/java/org/apache/james/examples/custom/listeners/BigMessageListenerTest.java b/examples/custom-listeners/src/test/java/org/apache/james/examples/custom/listeners/BigMessageListenerTest.java
new file mode 100644
index 0000000..5cdca0b
--- /dev/null
+++ b/examples/custom-listeners/src/test/java/org/apache/james/examples/custom/listeners/BigMessageListenerTest.java
@@ -0,0 +1,203 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.examples.custom.listeners;
+
+import static org.apache.james.examples.custom.listeners.BigMessageListener.BIG_MESSAGE;
+import static org.apache.james.examples.custom.listeners.BigMessageListener.ONE_MB;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.charset.StandardCharsets;
+import java.util.stream.Stream;
+
+import javax.mail.Flags;
+
+import org.apache.james.mailbox.DefaultMailboxes;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MailboxSessionUtil;
+import org.apache.james.mailbox.MessageIdManager;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.events.Event;
+import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
+import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.FetchGroupImpl;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.MessageMetaData;
+import org.apache.james.mailbox.model.MessageResult;
+import org.apache.james.mailbox.store.event.EventFactory;
+import org.apache.james.mime4j.dom.Message;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+
+class BigMessageListenerTest {
+
+    private static final String USER = "user";
+    private static final Event.EventId RANDOM_EVENT_ID = Event.EventId.random();
+    private static final MailboxPath INBOX_PATH = MailboxPath.forUser(USER, DefaultMailboxes.INBOX);
+
+    private BigMessageListener testee;
+    private MessageManager inboxMessageManager;
+    private MessageIdManager messageIdManager;
+    private MailboxId inboxId;
+    private MailboxSession mailboxSession;
+    private InMemoryMailboxManager mailboxManager;
+
+    @BeforeEach
+    void beforeEach() throws Exception {
+        InMemoryIntegrationResources resources = InMemoryIntegrationResources.defaultResources();
+        mailboxManager = resources.getMailboxManager();
+        messageIdManager = resources.getMessageIdManager();
+        mailboxSession = MailboxSessionUtil.create(USER);
+        inboxId = mailboxManager.createMailbox(INBOX_PATH, mailboxSession).get();
+        inboxMessageManager = mailboxManager.getMailbox(inboxId, mailboxSession);
+
+        testee = new BigMessageListener(mailboxManager, messageIdManager);
+
+        resources.getEventBus().register(testee);
+    }
+
+    @Test
+    void listeningEventShouldNotAddFlagWhenSmallMessages() throws Exception {
+        ComposedMessageId composedId = inboxMessageManager.appendMessage(
+            MessageManager.AppendCommand.builder()
+                .build(smallMessage()),
+            mailboxSession);
+
+        assertThat(getMessageFlags(composedId.getMessageId()))
+            .allSatisfy(flags -> assertThat(flags.contains(BIG_MESSAGE)).isFalse());
+    }
+
+    @Test
+    void listeningEventShouldNotRemoveOtherFlagsWhenSmallMessages() throws Exception {
+        Flags appendMessageFlag = new Flags();
+        appendMessageFlag.add(Flags.Flag.SEEN);
+        appendMessageFlag.add(Flags.Flag.DRAFT);
+
+        ComposedMessageId composedId = inboxMessageManager.appendMessage(
+            MessageManager.AppendCommand.builder()
+                .withFlags(appendMessageFlag)
+                .build(smallMessage()),
+            mailboxSession);
+
+        assertThat(getMessageFlags(composedId.getMessageId()))
+            .allSatisfy(flags -> {
+                assertThat(flags.contains(Flags.Flag.SEEN)).isTrue();
+                assertThat(flags.contains(Flags.Flag.DRAFT)).isTrue();
+            });
+    }
+
+    @Test
+    void listeningEventShouldAddFlagWhenBigMessages() throws Exception {
+        ComposedMessageId composedId = inboxMessageManager.appendMessage(
+            MessageManager.AppendCommand.builder()
+                .build(bigMessage()),
+            mailboxSession);
+
+        assertThat(getMessageFlags(composedId.getMessageId()))
+            .allSatisfy(flags -> assertThat(flags.contains(BIG_MESSAGE)).isTrue());
+    }
+
+    @Test
+    void eventShouldAddFlagWhenMessageSizeIsEqualToBigMessageSize() throws Exception {
+        ComposedMessageId composedIdOfSmallMessage = inboxMessageManager.appendMessage(
+            MessageManager.AppendCommand.builder()
+                .build(smallMessage()),
+            mailboxSession);
+
+        MessageResult addedMessage = messageIdManager
+            .getMessages(ImmutableList.of(composedIdOfSmallMessage.getMessageId()), FetchGroupImpl.MINIMAL, mailboxSession)
+            .get(0);
+        MessageMetaData oneMBMetaData = new MessageMetaData(addedMessage.getUid(), addedMessage.getModSeq(),
+            addedMessage.getFlags(), ONE_MB, addedMessage.getInternalDate(), addedMessage.getMessageId());
+
+        Event eventWithAFakeMessageSize = EventFactory.added()
+            .eventId(RANDOM_EVENT_ID)
+            .mailboxSession(mailboxSession)
+            .mailboxId(inboxId)
+            .mailboxPath(INBOX_PATH)
+            .addMetaData(oneMBMetaData)
+            .build();
+
+        testee.event(eventWithAFakeMessageSize);
+
+        assertThat(getMessageFlags(composedIdOfSmallMessage.getMessageId()))
+            .allSatisfy(flags -> assertThat(flags.contains(BIG_MESSAGE)).isTrue());
+    }
+
+    @Test
+    void listeningEventShouldNotRemoveOtherFlagsWhenBigMessages() throws Exception {
+        Flags appendMessageFlag = new Flags();
+        appendMessageFlag.add(Flags.Flag.SEEN);
+        appendMessageFlag.add(Flags.Flag.DRAFT);
+
+        ComposedMessageId composedId = inboxMessageManager.appendMessage(
+            MessageManager.AppendCommand.builder()
+                .withFlags(appendMessageFlag)
+                .build(bigMessage()),
+            mailboxSession);
+
+        assertThat(getMessageFlags(composedId.getMessageId()))
+            .allSatisfy(flags -> {
+                assertThat(flags.contains(Flags.Flag.SEEN)).isTrue();
+                assertThat(flags.contains(Flags.Flag.DRAFT)).isTrue();
+                assertThat(flags.contains(BIG_MESSAGE)).isTrue();
+            });
+    }
+
+    @Test
+    void listeningEventShouldKeepBigMessageFlagWhenAlreadySet() throws Exception {
+        Flags appendMessageFlag = new Flags();
+        appendMessageFlag.add(BIG_MESSAGE);
+
+        ComposedMessageId composedId = inboxMessageManager.appendMessage(
+            MessageManager.AppendCommand.builder()
+                .withFlags(appendMessageFlag)
+                .build(bigMessage()),
+            mailboxSession);
+
+        assertThat(getMessageFlags(composedId.getMessageId()))
+            .allSatisfy(flags -> assertThat(flags.contains(BIG_MESSAGE)).isTrue());
+    }
+
+    private Stream<Flags> getMessageFlags(MessageId messageId) throws Exception {
+        return messageIdManager.getMessages(ImmutableList.of(messageId), FetchGroupImpl.MINIMAL, mailboxSession)
+            .stream()
+            .map(MessageResult::getFlags);
+    }
+
+    private Message bigMessage() throws Exception {
+        return Message.Builder.of()
+            .setSubject("big message")
+            .setBody(Strings.repeat("big message has size greater than one MB", 1024 * 1024), StandardCharsets.UTF_8)
+            .build();
+    }
+
+    private Message smallMessage() throws Exception {
+        return Message.Builder.of()
+            .setSubject("small message")
+            .setBody("small message has size less than one MB", StandardCharsets.UTF_8)
+            .build();
+    }
+}
diff --git a/examples/pom.xml b/examples/pom.xml
index 084d87d..95b1b77 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -33,6 +33,7 @@
 
     <modules>
         <module>custom-mailets</module>
+        <module>custom-listeners</module>
     </modules>
 
 </project>
\ 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