JAMES-2342 Introduce a MessageMoveEvent
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/8b13708d Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/8b13708d Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/8b13708d Branch: refs/heads/master Commit: 8b13708dd9b96a8c30ba0a4155e515fafb19122b Parents: fdc0f83 Author: Antoine Duprat <[email protected]> Authored: Tue Mar 6 14:21:19 2018 +0100 Committer: Antoine Duprat <[email protected]> Committed: Thu Mar 8 11:01:22 2018 +0100 ---------------------------------------------------------------------- mailbox/plugin/spamassassin/pom.xml | 11 ++ .../spamassassin/SpamAssassinListener.java | 35 +++-- .../spamassassin/SpamAssassinListenerTest.java | 139 ++++++++++++------ .../mailbox/store/StoreMessageIdManager.java | 2 + .../mailbox/store/StoreMessageManager.java | 24 ++- .../event/DefaultDelegatingMailboxListener.java | 4 +- .../james/mailbox/store/event/EventFactory.java | 9 ++ .../store/event/MailboxEventDispatcher.java | 5 + .../mailbox/store/event/MessageMoveEvent.java | 109 ++++++++++++++ .../AbstractMessageIdManagerSideEffectTest.java | 3 + .../store/event/MessageMoveEventTest.java | 147 +++++++++++++++++++ .../SpamAssassinListenerModule.java | 9 +- 12 files changed, 435 insertions(+), 62 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/plugin/spamassassin/pom.xml ---------------------------------------------------------------------- diff --git a/mailbox/plugin/spamassassin/pom.xml b/mailbox/plugin/spamassassin/pom.xml index b510523..535c3f5 100644 --- a/mailbox/plugin/spamassassin/pom.xml +++ b/mailbox/plugin/spamassassin/pom.xml @@ -37,10 +37,21 @@ <artifactId>apache-james-mailbox-api</artifactId> </dependency> <dependency> + <groupId>org.apache.james</groupId> + <artifactId>apache-james-mailbox-api</artifactId> + <scope>test</scope> + <type>test-jar</type> + </dependency> + <dependency> <groupId>${project.groupId}</groupId> <artifactId>apache-james-mailbox-store</artifactId> </dependency> <dependency> + <groupId>org.apache.james</groupId> + <artifactId>apache-james-mailbox-memory</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/plugin/spamassassin/src/main/java/org/apache/james/mailbox/spamassassin/SpamAssassinListener.java ---------------------------------------------------------------------- diff --git a/mailbox/plugin/spamassassin/src/main/java/org/apache/james/mailbox/spamassassin/SpamAssassinListener.java b/mailbox/plugin/spamassassin/src/main/java/org/apache/james/mailbox/spamassassin/SpamAssassinListener.java index b2501f3..7a6382b 100644 --- a/mailbox/plugin/spamassassin/src/main/java/org/apache/james/mailbox/spamassassin/SpamAssassinListener.java +++ b/mailbox/plugin/spamassassin/src/main/java/org/apache/james/mailbox/spamassassin/SpamAssassinListener.java @@ -24,7 +24,11 @@ import javax.inject.Inject; import org.apache.james.mailbox.Event; import org.apache.james.mailbox.Role; -import org.apache.james.mailbox.store.event.EventFactory; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.store.MailboxSessionMapperFactory; +import org.apache.james.mailbox.store.event.MessageMoveEvent; import org.apache.james.mailbox.store.event.SpamEventListener; import org.apache.james.mailbox.store.mail.model.Message; import org.slf4j.Logger; @@ -40,10 +44,12 @@ public class SpamAssassinListener implements SpamEventListener { private static final Logger LOGGER = LoggerFactory.getLogger(SpamAssassinListener.class); private final SpamAssassin spamAssassin; + private final MailboxSessionMapperFactory mapperFactory; @Inject - public SpamAssassinListener(SpamAssassin spamAssassin) { + public SpamAssassinListener(SpamAssassin spamAssassin, MailboxSessionMapperFactory mapperFactory) { this.spamAssassin = spamAssassin; + this.mapperFactory = mapperFactory; } @Override @@ -58,25 +64,30 @@ public class SpamAssassinListener implements SpamEventListener { @Override public void event(Event event) { - LOGGER.debug("Event {} received in listener.", event); - if (event instanceof EventFactory.AddedImpl) { - EventFactory.AddedImpl addedToMailboxEvent = (EventFactory.AddedImpl) event; - if (isEventOnSpamMailbox(addedToMailboxEvent)) { + if (event instanceof MessageMoveEvent) { + MessageMoveEvent messageMoveEvent = (MessageMoveEvent) event; + if (isMessageMovedToSpamMailbox(messageMoveEvent)) { LOGGER.debug("Spam event detected"); - ImmutableList<InputStream> messages = addedToMailboxEvent.getAvailableMessages() + ImmutableList<InputStream> messages = messageMoveEvent.getMessages() .values() .stream() .map(Throwing.function(Message::getFullContent)) .collect(Guavate.toImmutableList()); - spamAssassin.learnSpam(messages, addedToMailboxEvent.getMailboxPath().getUser()); + spamAssassin.learnSpam(messages, messageMoveEvent.getSession().getUser().getUserName()); } } } @VisibleForTesting - boolean isEventOnSpamMailbox(MailboxEvent event) { - return Role.from(event.getMailboxPath().getName()) - .filter(role -> role.equals(Role.SPAM)) - .isPresent(); + boolean isMessageMovedToSpamMailbox(MessageMoveEvent event) { + try { + MailboxPath spamMailboxPath = MailboxPath.forUser(event.getSession().getUser().getUserName(), Role.SPAM.getDefaultMailbox()); + MailboxId spamMailboxId = mapperFactory.getMailboxMapper(event.getSession()).findMailboxByPath(spamMailboxPath).getMailboxId(); + + return event.getMessageMoves().addedMailboxIds().contains(spamMailboxId); + } catch (MailboxException e) { + LOGGER.warn("Could not resolve Spam mailbox", e); + return false; + } } } http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/plugin/spamassassin/src/test/java/org/apache/james/mailbox/spamassassin/SpamAssassinListenerTest.java ---------------------------------------------------------------------- diff --git a/mailbox/plugin/spamassassin/src/test/java/org/apache/james/mailbox/spamassassin/SpamAssassinListenerTest.java b/mailbox/plugin/spamassassin/src/test/java/org/apache/james/mailbox/spamassassin/SpamAssassinListenerTest.java index 72761da..eab5267 100644 --- a/mailbox/plugin/spamassassin/src/test/java/org/apache/james/mailbox/spamassassin/SpamAssassinListenerTest.java +++ b/mailbox/plugin/spamassassin/src/test/java/org/apache/james/mailbox/spamassassin/SpamAssassinListenerTest.java @@ -23,83 +23,132 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import java.util.Map; -import java.util.SortedMap; +import java.nio.charset.StandardCharsets; +import java.util.Date; + +import javax.mail.Flags; +import javax.mail.util.SharedByteArrayInputStream; -import org.apache.james.mailbox.DefaultMailboxes; -import org.apache.james.mailbox.MailboxListener.Added; -import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MessageUid; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.inmemory.InMemoryMailboxSessionMapperFactory; +import org.apache.james.mailbox.mock.MockMailboxSession; +import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.model.MailboxPath; -import org.apache.james.mailbox.model.MessageMetaData; -import org.apache.james.mailbox.store.event.EventFactory; -import org.apache.james.mailbox.store.mail.model.Mailbox; -import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.model.MessageMoves; +import org.apache.james.mailbox.model.TestMessageId; +import org.apache.james.mailbox.store.event.MessageMoveEvent; +import org.apache.james.mailbox.store.mail.MailboxMapper; +import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox; +import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage; +import org.junit.After; import org.junit.Before; import org.junit.Test; +import com.github.fge.lambdas.Throwing; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSortedMap; public class SpamAssassinListenerTest { + public static final String USER = "user"; + public static final MockMailboxSession MAILBOX_SESSION = new MockMailboxSession(USER); + public static final int UID_VALIDITY = 43; private SpamAssassin spamAssassin; private SpamAssassinListener listener; + private MailboxId mailboxId1; + private MailboxId mailboxId2; + private MailboxId spamMailboxId; + private MailboxId spamCapitalMailboxId; + private MailboxMapper mailboxMapper; @Before - public void setup() { + public void setup() throws MailboxException { spamAssassin = mock(SpamAssassin.class); - listener = new SpamAssassinListener(spamAssassin); + InMemoryMailboxSessionMapperFactory mapperFactory = new InMemoryMailboxSessionMapperFactory(); + mailboxMapper = mapperFactory.getMailboxMapper(MAILBOX_SESSION); + mailboxId1 = mailboxMapper.save(new SimpleMailbox(MailboxPath.forUser(USER, "mailbox1"), UID_VALIDITY)); + mailboxId2 = mailboxMapper.save(new SimpleMailbox(MailboxPath.forUser(USER, "mailbox2"), UID_VALIDITY)); + spamMailboxId = mailboxMapper.save(new SimpleMailbox(MailboxPath.forUser(USER, "Spam"), UID_VALIDITY)); + spamCapitalMailboxId = mailboxMapper.save(new SimpleMailbox(MailboxPath.forUser(USER, "SPAM"), UID_VALIDITY)); + + listener = new SpamAssassinListener(spamAssassin, mapperFactory); + } + + @After + public void tearDown() throws MailboxException { + mailboxMapper.list() + .forEach(Throwing.consumer(mailboxMapper::delete)); } @Test - public void isEventOnSpamMailboxShouldReturnFalseWhenMailboxIsNotSpam() { - MailboxSession mailboxSession = null; - int uidValidity = 1; - Mailbox mailbox = new SimpleMailbox(MailboxPath.forUser("user", "mbx"), uidValidity); - SortedMap<MessageUid, MessageMetaData> uids = ImmutableSortedMap.of(); - Map<MessageUid, MailboxMessage> availableMessages = ImmutableMap.of(); - Added added = new EventFactory().added(mailboxSession, uids, mailbox, availableMessages); - - assertThat(listener.isEventOnSpamMailbox(added)).isFalse(); + public void isEventOnSpamMailboxShouldReturnFalseWhenMessageIsMovedToANonSpamMailbox() { + MessageMoveEvent messageMoveEvent = MessageMoveEvent.builder() + .session(MAILBOX_SESSION) + .messageMoves(MessageMoves.builder() + .previousMailboxIds(mailboxId1) + .targetMailboxIds(mailboxId2) + .build()) + .messages(ImmutableMap.of(MessageUid.of(45), + createMessage(mailboxId2))) + .build(); + + assertThat(listener.isMessageMovedToSpamMailbox(messageMoveEvent)).isFalse(); } @Test public void isEventOnSpamMailboxShouldReturnTrueWhenMailboxIsSpam() { - MailboxSession mailboxSession = null; - int uidValidity = 1; - Mailbox mailbox = new SimpleMailbox(MailboxPath.forUser("user", DefaultMailboxes.SPAM), uidValidity); - SortedMap<MessageUid, MessageMetaData> uids = ImmutableSortedMap.of(); - Map<MessageUid, MailboxMessage> availableMessages = ImmutableMap.of(); - Added added = new EventFactory().added(mailboxSession, uids, mailbox, availableMessages); - - assertThat(listener.isEventOnSpamMailbox(added)).isTrue(); + MessageMoveEvent messageMoveEvent = MessageMoveEvent.builder() + .session(MAILBOX_SESSION) + .messageMoves(MessageMoves.builder() + .previousMailboxIds(mailboxId1) + .targetMailboxIds(spamMailboxId) + .build()) + .messages(ImmutableMap.of(MessageUid.of(45), + createMessage(mailboxId1))) + .build(); + + assertThat(listener.isMessageMovedToSpamMailbox(messageMoveEvent)).isTrue(); } @Test public void isEventOnSpamMailboxShouldReturnFalseWhenMailboxIsSpamOtherCase() { - MailboxSession mailboxSession = null; - int uidValidity = 1; - Mailbox mailbox = new SimpleMailbox(MailboxPath.forUser("user", "SPAM"), uidValidity); - SortedMap<MessageUid, MessageMetaData> uids = ImmutableSortedMap.of(); - Map<MessageUid, MailboxMessage> availableMessages = ImmutableMap.of(); - Added added = new EventFactory().added(mailboxSession, uids, mailbox, availableMessages); - - assertThat(listener.isEventOnSpamMailbox(added)).isFalse(); + MessageMoveEvent messageMoveEvent = MessageMoveEvent.builder() + .session(MAILBOX_SESSION) + .messageMoves(MessageMoves.builder() + .previousMailboxIds(mailboxId1) + .targetMailboxIds(spamCapitalMailboxId) + .build()) + .messages(ImmutableMap.of(MessageUid.of(45), + createMessage(mailboxId1))) + .build(); + + assertThat(listener.isMessageMovedToSpamMailbox(messageMoveEvent)).isFalse(); } @Test public void eventShouldCallSpamAssassinWhenTheEventMatches() { - MailboxSession mailboxSession = null; - int uidValidity = 1; - Mailbox mailbox = new SimpleMailbox(MailboxPath.forUser("user", "Spam"), uidValidity); - SortedMap<MessageUid, MessageMetaData> uids = ImmutableSortedMap.of(); - Map<MessageUid, MailboxMessage> availableMessages = ImmutableMap.of(); - Added added = new EventFactory().added(mailboxSession, uids, mailbox, availableMessages); - - listener.event(added); + MessageMoveEvent messageMoveEvent = MessageMoveEvent.builder() + .session(MAILBOX_SESSION) + .messageMoves(MessageMoves.builder() + .previousMailboxIds(mailboxId1) + .targetMailboxIds(spamMailboxId) + .build()) + .messages(ImmutableMap.of(MessageUid.of(45), + createMessage(mailboxId1))) + .build(); + + listener.event(messageMoveEvent); verify(spamAssassin).learnSpam(any(), any()); } + + private SimpleMailboxMessage createMessage(MailboxId mailboxId) { + int size = 45; + int bodyStartOctet = 25; + byte[] content = "Subject: test\r\n\r\nBody\r\n".getBytes(StandardCharsets.UTF_8); + return new SimpleMailboxMessage(TestMessageId.of(58), new Date(), + size, bodyStartOctet, new SharedByteArrayInputStream(content), new Flags(), new PropertyBuilder(), + mailboxId); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java index a4a448c..d65e6c6 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java @@ -68,6 +68,7 @@ import com.github.fge.lambdas.Throwing; import com.github.fge.lambdas.functions.ThrowingFunction; import com.github.steveash.guavate.Guavate; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; public class StoreMessageIdManager implements MessageIdManager { @@ -231,6 +232,7 @@ public class StoreMessageIdManager implements MessageIdManager { addMessageToMailboxes(mailboxMessage, messageMoves.addedMailboxIds(), mailboxSession); removeMessageFromMailboxes(mailboxMessage, messageMoves.removedMailboxIds(), mailboxSession); + dispatcher.moved(mailboxSession, messageMoves, ImmutableMap.of(mailboxMessage.getUid(), mailboxMessage)); } private void removeMessageFromMailboxes(MailboxMessage message, Set<MailboxId> mailboxesToRemove, MailboxSession mailboxSession) throws MailboxException { http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java index 23d9108..c095100 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java @@ -55,6 +55,7 @@ import org.apache.james.mailbox.model.MessageAttachment; import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MessageId.Factory; import org.apache.james.mailbox.model.MessageMetaData; +import org.apache.james.mailbox.model.MessageMoves; import org.apache.james.mailbox.model.MessageRange; import org.apache.james.mailbox.model.MessageResult.FetchGroup; import org.apache.james.mailbox.model.MessageResultIterator; @@ -740,7 +741,22 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana private SortedMap<MessageUid, MessageMetaData> copy(MessageRange set, StoreMessageManager to, MailboxSession session) throws MailboxException { IteratorWrapper<MailboxMessage> originalRows = new IteratorWrapper<>(retrieveOriginalRows(set, session)); - return collectMetadata(to.copy(originalRows, session)); + + SortedMap<MessageUid, MessageMetaData> copiedUids = collectMetadata(to.copy(originalRows, session)); + + ImmutableMap.Builder<MessageUid, MailboxMessage> messagesMap = ImmutableMap.builder(); + for (MailboxMessage message: originalRows.getEntriesSeen()) { + messagesMap.put(message.getUid(), immutableMailboxMessageFactory.from(to.getMailboxEntity().getMailboxId(), message)); + } + dispatcher.added(session, copiedUids, to.getMailboxEntity(), messagesMap.build()); + dispatcher.moved(session, + MessageMoves.builder() + .previousMailboxIds(getMailboxEntity().getMailboxId()) + .targetMailboxIds(to.getMailboxEntity().getMailboxId(), getMailboxEntity().getMailboxId()) + .build(), + messagesMap.build()); + + return copiedUids; } private SortedMap<MessageUid, MessageMetaData> move(MessageRange set, StoreMessageManager to, MailboxSession session) throws MailboxException { @@ -755,6 +771,12 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana } dispatcher.added(session, moveUids, to.getMailboxEntity(), messagesMap.build()); dispatcher.expunged(session, collectMetadata(moveResult.getOriginalMessages()), getMailboxEntity()); + dispatcher.moved(session, + MessageMoves.builder() + .previousMailboxIds(getMailboxEntity().getMailboxId()) + .targetMailboxIds(to.getMailboxEntity().getMailboxId()) + .build(), + messagesMap.build()); return moveUids; } http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListener.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListener.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListener.java index 687ff22..dca2f0c 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListener.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/DefaultDelegatingMailboxListener.java @@ -88,6 +88,7 @@ public class DefaultDelegatingMailboxListener implements DelegatingMailboxListen @Override public void event(Event event) { + deliverEventToGlobalListeners(event); if (event instanceof MailboxEvent) { mailboxEvent((MailboxEvent) event); } @@ -102,7 +103,6 @@ public class DefaultDelegatingMailboxListener implements DelegatingMailboxListen registry.handleRename(renamed.getMailboxPath(), renamed.getNewPath()); } deliverEventToMailboxListeners(mailboxEvent, listenerSnapshot); - deliverEventToGlobalListeners(mailboxEvent); } protected void deliverEventToMailboxListeners(MailboxEvent event, Collection<MailboxListener> listenerSnapshot) { @@ -111,7 +111,7 @@ public class DefaultDelegatingMailboxListener implements DelegatingMailboxListen } } - protected void deliverEventToGlobalListeners(MailboxEvent event) { + protected void deliverEventToGlobalListeners(Event event) { for (MailboxListener mailboxListener : registry.getGlobalListeners()) { eventDelivery.deliver(mailboxListener, event); } http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java index b7cb1a2..040219a 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java @@ -29,6 +29,7 @@ import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.acl.ACLDiff; import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.mailbox.model.MessageMetaData; +import org.apache.james.mailbox.model.MessageMoves; import org.apache.james.mailbox.model.UpdatedFlags; import org.apache.james.mailbox.store.StoreMailboxPath; import org.apache.james.mailbox.store.mail.model.Mailbox; @@ -202,4 +203,12 @@ public class EventFactory { public MailboxListener.MailboxACLUpdated aclUpdated(MailboxSession session, MailboxPath mailboxPath, ACLDiff aclDiff) { return new MailboxListener.MailboxACLUpdated(session, mailboxPath, aclDiff); } + + public MessageMoveEvent moved(MailboxSession session, MessageMoves messageMoves, Map<MessageUid, MailboxMessage> messages) { + return MessageMoveEvent.builder() + .session(session) + .messageMoves(messageMoves) + .messages(messages) + .build(); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxEventDispatcher.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxEventDispatcher.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxEventDispatcher.java index 0f628a1..e64a18f 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxEventDispatcher.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MailboxEventDispatcher.java @@ -31,6 +31,7 @@ import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.acl.ACLDiff; import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.mailbox.model.MessageMetaData; +import org.apache.james.mailbox.model.MessageMoves; import org.apache.james.mailbox.model.UpdatedFlags; import org.apache.james.mailbox.store.SimpleMessageMetaData; import org.apache.james.mailbox.store.mail.model.Mailbox; @@ -153,4 +154,8 @@ public class MailboxEventDispatcher { public void aclUpdated(MailboxSession session, MailboxPath mailboxPath, ACLDiff aclDiff) { listener.event(eventFactory.aclUpdated(session, mailboxPath, aclDiff)); } + + public void moved(MailboxSession session, MessageMoves messageMoves, Map<MessageUid, MailboxMessage> messages) { + listener.event(eventFactory.moved(session, messageMoves, messages)); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MessageMoveEvent.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MessageMoveEvent.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MessageMoveEvent.java new file mode 100644 index 0000000..8fe8c55 --- /dev/null +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/MessageMoveEvent.java @@ -0,0 +1,109 @@ +/**************************************************************** + * 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.mailbox.store.event; + +import java.util.Map; + +import org.apache.james.mailbox.Event; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.MessageUid; +import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MessageMoves; +import org.apache.james.mailbox.store.mail.model.MailboxMessage; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; + +public class MessageMoveEvent implements Event { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private MailboxSession session; + private MessageMoves messageMoves; + private ImmutableMap.Builder<MessageUid, MailboxMessage> messagesBuilder; + + private Builder() { + messagesBuilder = ImmutableMap.builder(); + } + + public Builder session(MailboxSession session) { + this.session = session; + return this; + } + + public Builder messageMoves(MessageMoves messageMoves) { + this.messageMoves = messageMoves; + return this; + } + + public Builder messages(Map<MessageUid, MailboxMessage> messages) { + this.messagesBuilder.putAll(messages); + return this; + } + + public MessageMoveEvent build() { + Preconditions.checkNotNull(session, "'session' is mandatory"); + Preconditions.checkNotNull(messageMoves, "'messageMoves' is mandatory"); + + ImmutableMap<MessageUid, MailboxMessage> messages = messagesBuilder.build(); + Preconditions.checkArgument(!messages.isEmpty(), "'messages' should not be empty"); + + return new MessageMoveEvent(session, messageMoves, messages); + } + } + + private final MailboxSession session; + private final MessageMoves messageMoves; + private final Map<MessageUid, MailboxMessage> messages; + + @VisibleForTesting + MessageMoveEvent(MailboxSession session, MessageMoves messageMoves, Map<MessageUid, MailboxMessage> messages) { + this.session = session; + this.messageMoves = messageMoves; + this.messages = messages; + } + + @Override + public MailboxSession getSession() { + return session; + } + + public MessageMoves getMessageMoves() { + return messageMoves; + } + + public Map<MessageUid, MailboxMessage> getMessages() { + return messages; + } + + public boolean isMoveTo(MailboxId mailboxId) { + return messageMoves.addedMailboxIds() + .contains(mailboxId); + } + + public boolean isMoveFrom(MailboxId mailboxId) { + return messageMoves.removedMailboxIds() + .contains(mailboxId); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java index 1a7d0a5..3afdaf6 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java @@ -142,6 +142,7 @@ public abstract class AbstractMessageIdManagerSideEffectTest { messageIdManager.setInMailboxes(messageId, ImmutableList.of(mailbox1.getMailboxId(), mailbox2.getMailboxId()), session); verify(dispatcher).added(eq(session), eq(mailbox1), any(MailboxMessage.class)); + verify(dispatcher).moved(eq(session), any(), any()); verifyNoMoreInteractions(dispatcher); } @@ -157,6 +158,7 @@ public abstract class AbstractMessageIdManagerSideEffectTest { verify(dispatcher).added(eq(session), eq(mailbox1), any(MailboxMessage.class)); verify(dispatcher).added(eq(session), eq(mailbox3), any(MailboxMessage.class)); + verify(dispatcher).moved(eq(session), any(), any()); verifyNoMoreInteractions(dispatcher); } @@ -186,6 +188,7 @@ public abstract class AbstractMessageIdManagerSideEffectTest { verify(dispatcher).expunged(eq(session), any(SimpleMessageMetaData.class), eq(mailbox2)); verify(dispatcher).added(eq(session), eq(mailbox3), any(MailboxMessage.class)); + verify(dispatcher).moved(eq(session), any(), any()); verifyNoMoreInteractions(dispatcher); } http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/mailbox/store/src/test/java/org/apache/james/mailbox/store/event/MessageMoveEventTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/event/MessageMoveEventTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/event/MessageMoveEventTest.java new file mode 100644 index 0000000..5052ff8 --- /dev/null +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/event/MessageMoveEventTest.java @@ -0,0 +1,147 @@ +/**************************************************************** + * 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.mailbox.store.event; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +import java.util.Map; + +import org.apache.james.mailbox.MessageUid; +import org.apache.james.mailbox.mock.MockMailboxSession; +import org.apache.james.mailbox.model.MessageMoves; +import org.apache.james.mailbox.model.TestId; +import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.assertj.core.api.JUnitSoftAssertions; +import org.junit.Rule; +import org.junit.Test; + +import com.google.common.collect.ImmutableMap; + +public class MessageMoveEventTest { + + @Rule + public JUnitSoftAssertions softly = new JUnitSoftAssertions(); + + @Test + public void builderShouldThrowWhenSessionIsNull() { + assertThatThrownBy(() -> MessageMoveEvent.builder() + .build()) + .isInstanceOf(NullPointerException.class); + } + + @Test + public void builderShouldThrowWhenMessageMovesIsNull() { + assertThatThrownBy(() -> MessageMoveEvent.builder() + .session(new MockMailboxSession("[email protected]")) + .build()) + .isInstanceOf(NullPointerException.class); + } + + @Test + public void builderShouldThrowWhenMessagesIsEmpty() { + assertThatThrownBy(() -> MessageMoveEvent.builder() + .session(new MockMailboxSession("[email protected]")) + .messageMoves(MessageMoves.builder() + .previousMailboxIds(TestId.of(1)) + .targetMailboxIds(TestId.of(2)) + .build()) + .build()) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void builderShouldBuildWhenFieldsAreGiven() { + MockMailboxSession session = new MockMailboxSession("[email protected]"); + MessageMoves messageMoves = MessageMoves.builder() + .targetMailboxIds(TestId.of(2)) + .previousMailboxIds(TestId.of(1)) + .build(); + Map<MessageUid, MailboxMessage> messages = ImmutableMap.of(MessageUid.of(1), mock(MailboxMessage.class)); + + MessageMoveEvent event = MessageMoveEvent.builder() + .session(session) + .messageMoves(messageMoves) + .messages(messages) + .build(); + + softly.assertThat(event.getSession()).isEqualTo(session); + softly.assertThat(event.getMessageMoves()).isEqualTo(messageMoves); + softly.assertThat(event.getMessages()).isEqualTo(messages); + } + + @Test + public void isMoveToShouldReturnFalseWhenMailboxIdIsNotInAddedMailboxIds() { + MessageMoveEvent event = MessageMoveEvent.builder() + .session(new MockMailboxSession("[email protected]")) + .messageMoves(MessageMoves.builder() + .previousMailboxIds(TestId.of(1)) + .targetMailboxIds(TestId.of(2)) + .build()) + .messages(ImmutableMap.of(MessageUid.of(1), mock(MailboxMessage.class))) + .build(); + + assertThat(event.isMoveTo(TestId.of(123))).isFalse(); + } + + @Test + public void isMoveToShouldReturnTrueWhenMailboxIdIsInAddedMailboxIds() { + TestId mailboxId = TestId.of(123); + MessageMoveEvent event = MessageMoveEvent.builder() + .session(new MockMailboxSession("[email protected]")) + .messageMoves(MessageMoves.builder() + .previousMailboxIds(TestId.of(1)) + .targetMailboxIds(TestId.of(2), mailboxId) + .build()) + .messages(ImmutableMap.of(MessageUid.of(1), mock(MailboxMessage.class))) + .build(); + + assertThat(event.isMoveTo(mailboxId)).isTrue(); + } + + @Test + public void isMoveFromShouldReturnFalseWhenMailboxIdIsNotInRemovedMailboxIds() { + MessageMoveEvent event = MessageMoveEvent.builder() + .session(new MockMailboxSession("[email protected]")) + .messageMoves(MessageMoves.builder() + .previousMailboxIds(TestId.of(1)) + .targetMailboxIds(TestId.of(2)) + .build()) + .messages(ImmutableMap.of(MessageUid.of(1), mock(MailboxMessage.class))) + .build(); + + assertThat(event.isMoveFrom(TestId.of(123))).isFalse(); + } + + @Test + public void isMoveFromShouldReturnTrueWhenMailboxIdIsInRemovedMailboxIds() { + TestId mailboxId = TestId.of(123); + MessageMoveEvent event = MessageMoveEvent.builder() + .session(new MockMailboxSession("[email protected]")) + .messageMoves(MessageMoves.builder() + .previousMailboxIds(TestId.of(1), mailboxId) + .targetMailboxIds(TestId.of(2)) + .build()) + .messages(ImmutableMap.of(MessageUid.of(1), mock(MailboxMessage.class))) + .build(); + + assertThat(event.isMoveFrom(mailboxId)).isTrue(); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/8b13708d/server/container/guice/mailbox-plugin-spamassassin/src/main/java/org/apache/james/modules/spamassassin/SpamAssassinListenerModule.java ---------------------------------------------------------------------- diff --git a/server/container/guice/mailbox-plugin-spamassassin/src/main/java/org/apache/james/modules/spamassassin/SpamAssassinListenerModule.java b/server/container/guice/mailbox-plugin-spamassassin/src/main/java/org/apache/james/modules/spamassassin/SpamAssassinListenerModule.java index 8054bd4..6fe431f 100644 --- a/server/container/guice/mailbox-plugin-spamassassin/src/main/java/org/apache/james/modules/spamassassin/SpamAssassinListenerModule.java +++ b/server/container/guice/mailbox-plugin-spamassassin/src/main/java/org/apache/james/modules/spamassassin/SpamAssassinListenerModule.java @@ -32,6 +32,7 @@ import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.spamassassin.SpamAssassin; import org.apache.james.mailbox.spamassassin.SpamAssassinConfiguration; import org.apache.james.mailbox.spamassassin.SpamAssassinListener; +import org.apache.james.mailbox.store.MailboxSessionMapperFactory; import org.apache.james.mailbox.store.StoreMailboxManager; import org.apache.james.utils.ConfigurationPerformer; import org.apache.james.utils.PropertiesProvider; @@ -60,17 +61,21 @@ public class SpamAssassinListenerModule extends AbstractModule { private final SpamAssassinConfiguration spamAssassinConfiguration; private final StoreMailboxManager storeMailboxManager; + private final MailboxSessionMapperFactory mapperFactory; @Inject - public SpamAssassinListenerConfigurationPerformer(SpamAssassinConfiguration spamAssassinConfiguration, StoreMailboxManager storeMailboxManager) { + public SpamAssassinListenerConfigurationPerformer(SpamAssassinConfiguration spamAssassinConfiguration, + StoreMailboxManager storeMailboxManager, + MailboxSessionMapperFactory mapperFactory) { this.spamAssassinConfiguration = spamAssassinConfiguration; this.storeMailboxManager = storeMailboxManager; + this.mapperFactory = mapperFactory; } @Override public void initModule() { try { - SpamAssassinListener spamAssassinListener = new SpamAssassinListener(new SpamAssassin(spamAssassinConfiguration)); + SpamAssassinListener spamAssassinListener = new SpamAssassinListener(new SpamAssassin(spamAssassinConfiguration), mapperFactory); MailboxSession session = null; storeMailboxManager.addGlobalListener(spamAssassinListener, session); } catch (MailboxException e) { --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
