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 9a59a5456cd0e5eb1c528c6b4179e83c19933beb
Author: datph <[email protected]>
AuthorDate: Fri Mar 1 16:29:15 2019 +0700

    JAMES-2662 Implement DeletedMessageVaultHook
---
 mailbox/plugin/deleted-messages-vault/pom.xml      |  15 ++
 .../james/vault/DeletedMessageConverter.java       |  58 ++---
 .../apache/james/vault/DeletedMessageMetadata.java |  84 ------
 .../james/vault/DeletedMessageVaultHook.java       | 168 ++++++++++++
 .../james/vault/DeletedMessageConverterTest.java   |  25 +-
 .../apache/james/vault/DeletedMessageFixture.java  |   2 +
 ....java => DeletedMessageMailboxContextTest.java} |   3 +-
 .../james/vault/DeletedMessageVaultHookTest.java   | 289 +++++++++++++++++++++
 8 files changed, 511 insertions(+), 133 deletions(-)

diff --git a/mailbox/plugin/deleted-messages-vault/pom.xml 
b/mailbox/plugin/deleted-messages-vault/pom.xml
index 5423077..1063fb4 100644
--- a/mailbox/plugin/deleted-messages-vault/pom.xml
+++ b/mailbox/plugin/deleted-messages-vault/pom.xml
@@ -43,7 +43,22 @@
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>apache-james-mailbox-memory</artifactId>
+        </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-store</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-store</artifactId>
+            <scope>test</scope>
+            <type>test-jar</type>
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
diff --git 
a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageConverter.java
 
b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageConverter.java
index 9c9516b..faacaf7 100644
--- 
a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageConverter.java
+++ 
b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageConverter.java
@@ -20,7 +20,6 @@
 package org.apache.james.vault;
 
 import java.io.IOException;
-import java.time.Clock;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.util.Date;
@@ -34,7 +33,6 @@ import javax.mail.internet.AddressException;
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
 import org.apache.james.core.User;
-import org.apache.james.mailbox.store.mail.model.MailboxMessage;
 import org.apache.james.mime4j.MimeIOException;
 import org.apache.james.mime4j.codec.DecodeMonitor;
 import org.apache.james.mime4j.dom.Message;
@@ -54,53 +52,47 @@ class DeletedMessageConverter {
 
     private static final Logger LOGGER = 
LoggerFactory.getLogger(DeletedMessageConverter.class);
 
-    private final Clock clock;
+    DeletedMessage 
convert(DeletedMessageVaultHook.DeletedMessageMailboxContext 
deletedMessageMailboxContext, org.apache.james.mailbox.store.mail.model.Message 
message, ZonedDateTime deletionDate) throws IOException {
+        Preconditions.checkNotNull(deletedMessageMailboxContext);
+        Preconditions.checkNotNull(message);
 
-    DeletedMessageConverter(Clock clock) {
-        this.clock = clock;
-    }
-
-    DeletedMessage convert(DeletedMessageMetadata deletedMessageMetadata, 
MailboxMessage mailboxMessage) throws IOException {
-        Preconditions.checkNotNull(deletedMessageMetadata);
-        Preconditions.checkNotNull(mailboxMessage);
-
-        Optional<Message> mimeMessage = parseMessage(mailboxMessage);
+        Optional<Message> mimeMessage = parseMessage(message);
 
         return DeletedMessage.builder()
-            .messageId(deletedMessageMetadata.getMessageId())
-            .originMailboxes(deletedMessageMetadata.getOwnerMailboxes())
-            .user(retrieveOwner(deletedMessageMetadata))
-            .deliveryDate(retrieveDeliveryDate(mimeMessage, mailboxMessage))
-            .deletionDate(ZonedDateTime.ofInstant(clock.instant(), 
ZoneOffset.UTC))
+            .messageId(deletedMessageMailboxContext.getMessageId())
+            .originMailboxes(deletedMessageMailboxContext.getOwnerMailboxes())
+            .user(retrieveOwner(deletedMessageMailboxContext))
+            .deliveryDate(retrieveDeliveryDate(mimeMessage, message))
+            .deletionDate(deletionDate)
             .sender(retrieveSender(mimeMessage))
             .recipients(retrieveRecipients(mimeMessage))
-            
.hasAttachment(mailboxMessage.getAttachments().iterator().hasNext())
+            .hasAttachment(!message.getAttachments().isEmpty())
             .subject(mimeMessage.map(Message::getSubject))
             .build();
     }
 
-    private Optional<Message> parseMessage(MailboxMessage mailboxMessage) 
throws IOException {
+    private Optional<Message> 
parseMessage(org.apache.james.mailbox.store.mail.model.Message message) throws 
IOException {
         DefaultMessageBuilder messageBuilder = new DefaultMessageBuilder();
         messageBuilder.setMimeEntityConfig(MimeConfig.PERMISSIVE);
         messageBuilder.setDecodeMonitor(DecodeMonitor.SILENT);
         try {
-            return 
Optional.ofNullable(messageBuilder.parseMessage(mailboxMessage.getFullContent()));
+            return 
Optional.ofNullable(messageBuilder.parseMessage(message.getFullContent()));
         } catch (MimeIOException e) {
-            LOGGER.warn("Can not parse the message {}", 
mailboxMessage.getUid(), e);
+            LOGGER.warn("Can not parse the message {}", 
message.getMessageId(), e);
             return Optional.empty();
         }
     }
 
-    private User retrieveOwner(DeletedMessageMetadata metadata) {
-        Preconditions.checkNotNull(metadata.getOwner(), "Deleted mail is 
missing owner");
-        return metadata.getOwner();
+    private User 
retrieveOwner(DeletedMessageVaultHook.DeletedMessageMailboxContext 
deletedMessageMailboxContext) {
+        Preconditions.checkNotNull(deletedMessageMailboxContext.getOwner(), 
"Deleted mail is missing owner");
+        return deletedMessageMailboxContext.getOwner();
     }
 
-    private ZonedDateTime retrieveDeliveryDate(Optional<Message> mimeMessage, 
MailboxMessage mailboxMessage) {
+    private ZonedDateTime retrieveDeliveryDate(Optional<Message> mimeMessage, 
org.apache.james.mailbox.store.mail.model.Message message) {
         return mimeMessage.map(Message::getDate)
             .map(Date::toInstant)
             .map(instant -> ZonedDateTime.ofInstant(instant, ZoneOffset.UTC))
-            
.orElse(ZonedDateTime.ofInstant(mailboxMessage.getInternalDate().toInstant(), 
ZoneOffset.UTC));
+            
.orElse(ZonedDateTime.ofInstant(message.getInternalDate().toInstant(), 
ZoneOffset.UTC));
     }
 
     private MaybeSender retrieveSender(Optional<Message> mimeMessage) {
@@ -113,11 +105,10 @@ class DeletedMessageConverter {
 
     private List<MailAddress> retrieveRecipients(Optional<Message> message) {
         return StreamUtils.flatten(combineRecipients(message)
-                .filter(Objects::nonNull)
-                .map(AddressList::flatten)
-                .flatMap(MailboxList::stream)
-                .map(Mailbox::getAddress)
-                .map(this::retrieveAddress))
+            .map(AddressList::flatten)
+            .flatMap(MailboxList::stream)
+            .map(Mailbox::getAddress)
+            .map(this::retrieveAddress))
             .collect(Guavate.toImmutableList());
     }
 
@@ -132,8 +123,9 @@ class DeletedMessageConverter {
 
     private Stream<AddressList> combineRecipients(Optional<Message> message) {
         return message.map(mimeMessage -> Stream.of(mimeMessage.getTo(),
-                mimeMessage.getCc(),
-                mimeMessage.getBcc()))
+                    mimeMessage.getCc(),
+                    mimeMessage.getBcc())
+                .filter(Objects::nonNull))
             .orElse(Stream.of());
     }
 }
diff --git 
a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageMetadata.java
 
b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageMetadata.java
deleted file mode 100644
index 9215ebd..0000000
--- 
a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageMetadata.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.vault;
-
-import java.util.List;
-import java.util.Objects;
-
-import org.apache.james.core.User;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MessageId;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
-class DeletedMessageMetadata {
-    private final MessageId messageId;
-    private final User owner;
-    private final List<MailboxId> ownerMailboxes;
-
-    DeletedMessageMetadata(MessageId messageId, User owner, List<MailboxId> 
ownerMailboxes) {
-        this.messageId = messageId;
-        this.owner = owner;
-        this.ownerMailboxes = ownerMailboxes;
-    }
-
-    DeletedMessageMetadata combineWith(DeletedMessageMetadata other) {
-        Preconditions.checkArgument(messageId.equals(other.messageId));
-        Preconditions.checkArgument(owner.equals(other.owner));
-
-        return new DeletedMessageMetadata(
-            messageId,
-            owner,
-            ImmutableList.<MailboxId>builder()
-                .addAll(ownerMailboxes)
-                .addAll(other.ownerMailboxes)
-                .build());
-    }
-
-    public MessageId getMessageId() {
-        return messageId;
-    }
-
-    public User getOwner() {
-        return owner;
-    }
-
-    public List<MailboxId> getOwnerMailboxes() {
-        return ownerMailboxes;
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof DeletedMessageMetadata) {
-            DeletedMessageMetadata that = (DeletedMessageMetadata) o;
-
-            return Objects.equals(this.messageId, that.messageId)
-                && Objects.equals(this.owner, that.owner)
-                && Objects.equals(this.ownerMailboxes, that.ownerMailboxes);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(messageId, owner, ownerMailboxes);
-    }
-}
diff --git 
a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java
 
b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java
new file mode 100644
index 0000000..539da4d
--- /dev/null
+++ 
b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultHook.java
@@ -0,0 +1,168 @@
+/****************************************************************
+ * 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.vault;
+
+import java.time.Clock;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.core.User;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MetadataWithMailboxId;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
+import org.apache.james.mailbox.store.SessionProvider;
+import org.apache.james.mailbox.store.mail.MessageMapper;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+import org.reactivestreams.Publisher;
+
+import com.github.fge.lambdas.Throwing;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.GroupedFlux;
+import reactor.core.publisher.Mono;
+
+public class DeletedMessageVaultHook implements PreDeletionHook {
+    static class DeletedMessageMailboxContext {
+        private static DeletedMessageMailboxContext 
combine(DeletedMessageMailboxContext first, DeletedMessageMailboxContext 
second) {
+            
Preconditions.checkArgument(first.messageId.equals(second.getMessageId()));
+            Preconditions.checkArgument(first.owner.equals(second.getOwner()));
+
+            return new DeletedMessageMailboxContext(
+                first.messageId,
+                first.owner,
+                ImmutableList.<MailboxId>builder()
+                    .addAll(first.ownerMailboxes)
+                    .addAll(second.ownerMailboxes)
+                    .build());
+        }
+
+        private final MessageId messageId;
+        private final User owner;
+        private final List<MailboxId> ownerMailboxes;
+
+        DeletedMessageMailboxContext(MessageId messageId, User owner, 
List<MailboxId> ownerMailboxes) {
+            this.messageId = messageId;
+            this.owner = owner;
+            this.ownerMailboxes = ownerMailboxes;
+        }
+
+        MessageId getMessageId() {
+            return messageId;
+        }
+
+        User getOwner() {
+            return owner;
+        }
+
+        List<MailboxId> getOwnerMailboxes() {
+            return ownerMailboxes;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof DeletedMessageMailboxContext) {
+                DeletedMessageMailboxContext that = 
(DeletedMessageMailboxContext) o;
+
+                return Objects.equals(this.messageId, that.getMessageId())
+                    && Objects.equals(this.owner, that.getOwner())
+                    && Objects.equals(this.ownerMailboxes, 
that.getOwnerMailboxes());
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(messageId, owner, ownerMailboxes);
+        }
+    }
+
+    private final MailboxSession session;
+    private final DeletedMessageVault deletedMessageVault;
+    private final DeletedMessageConverter deletedMessageConverter;
+    private final MailboxSessionMapperFactory mapperFactory;
+    private final Clock clock;
+
+    DeletedMessageVaultHook(SessionProvider sessionProvider,
+                            DeletedMessageVault deletedMessageVault,
+                            DeletedMessageConverter deletedMessageConverter,
+                            MailboxSessionMapperFactory mapperFactory,
+                            Clock clock) {
+        this.session = 
sessionProvider.createSystemSession(getClass().getName());
+        this.deletedMessageVault = deletedMessageVault;
+        this.deletedMessageConverter = deletedMessageConverter;
+        this.mapperFactory = mapperFactory;
+        this.clock = clock;
+    }
+
+    @Override
+    public Publisher<Void> notifyDelete(DeleteOperation deleteOperation) {
+        Preconditions.checkNotNull(deleteOperation);
+
+        return groupMetadataByOwnerAndMessageId(deleteOperation)
+            .flatMap(Throwing.function(this::appendToTheVault).sneakyThrow())
+            .then();
+    }
+
+    private Mono<Void> appendToTheVault(DeletedMessageMailboxContext 
deletedMessageMailboxContext) throws MailboxException {
+        Optional<MailboxMessage> maybeMailboxMessage = 
mapperFactory.getMessageIdMapper(session)
+            
.find(ImmutableList.of(deletedMessageMailboxContext.getMessageId()), 
MessageMapper.FetchType.Full).stream()
+            .findFirst();
+
+        return maybeMailboxMessage.map(Throwing.function(mailboxMessage -> 
Pair.of(mailboxMessage,
+                deletedMessageConverter.convert(deletedMessageMailboxContext, 
mailboxMessage,
+                    ZonedDateTime.ofInstant(clock.instant(), 
ZoneOffset.UTC)))))
+            .map(Throwing.function(pairs -> Mono.from(deletedMessageVault
+                .append(pairs.getRight().getOwner(), pairs.getRight(), 
pairs.getLeft().getFullContent()))))
+            .orElse(Mono.empty());
+    }
+
+    private Flux<DeletedMessageMailboxContext> 
groupMetadataByOwnerAndMessageId(DeleteOperation deleteOperation) {
+        return Flux.fromIterable(deleteOperation.getDeletionMetadataList())
+            .groupBy(MetadataWithMailboxId::getMailboxId)
+            .flatMap(Throwing.function(this::addOwnerToMetadata).sneakyThrow())
+            .groupBy(this::toMessageIdUserPair)
+            .flatMap(groupFlux -> 
groupFlux.reduce(DeletedMessageMailboxContext::combine));
+    }
+
+    private Publisher<DeletedMessageMailboxContext> 
addOwnerToMetadata(GroupedFlux<MailboxId, MetadataWithMailboxId> groupedFlux) 
throws MailboxException {
+        User owner = retrieveMailboxUser(groupedFlux.key());
+        return groupedFlux.map(metadata -> new 
DeletedMessageMailboxContext(metadata.getMessageMetaData().getMessageId(), 
owner, ImmutableList.of(metadata.getMailboxId())));
+    }
+
+    private Pair<MessageId, User> 
toMessageIdUserPair(DeletedMessageMailboxContext deletedMessageMetadata) {
+        return Pair.of(deletedMessageMetadata.getMessageId(), 
deletedMessageMetadata.getOwner());
+    }
+
+    private User retrieveMailboxUser(MailboxId mailboxId) throws 
MailboxException {
+        return User.fromUsername(mapperFactory.getMailboxMapper(session)
+            .findMailboxById(mailboxId)
+            .getUser());
+    }
+}
\ No newline at end of file
diff --git 
a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageConverterTest.java
 
b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageConverterTest.java
index 74f7f88..9cea8d0 100644
--- 
a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageConverterTest.java
+++ 
b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageConverterTest.java
@@ -35,8 +35,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.nio.charset.StandardCharsets;
-import java.time.Clock;
-import java.time.ZoneOffset;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
@@ -64,7 +62,7 @@ class DeletedMessageConverterTest {
     private static final String CC_FIELD = "cc";
 
     private static final List<MailboxId> ORIGIN_MAILBOXES = 
ImmutableList.of(MAILBOX_ID_1, MAILBOX_ID_2);
-    private static final DeletedMessageMetadata DELETED_MESSAGE_METADATA = new 
DeletedMessageMetadata(
+    private static final DeletedMessageVaultHook.DeletedMessageMailboxContext 
DELETED_MESSAGE_MAILBOX_CONTEXT = new 
DeletedMessageVaultHook.DeletedMessageMailboxContext(
         DeletedMessageFixture.MESSAGE_ID,
         USER,
         ORIGIN_MAILBOXES);
@@ -102,14 +100,13 @@ class DeletedMessageConverterTest {
 
     @BeforeEach
     void setUp() {
-        Clock clock = Clock.fixed(DELETION_DATE.toInstant(), ZoneOffset.UTC);
-        deletedMessageConverter = new DeletedMessageConverter(clock);
+        deletedMessageConverter = new DeletedMessageConverter();
     }
 
     @Test
     void convertShouldThrowWhenNoOwner() {
-        DeletedMessageMetadata deletedMessageMetadata = new 
DeletedMessageMetadata(MESSAGE_ID, EMPTY_OWNER, ORIGIN_MAILBOXES);
-        assertThatThrownBy(() -> 
deletedMessageConverter.convert(deletedMessageMetadata, 
buildMessage(getMessageBuilder(), ATTACHMENTS)))
+        DeletedMessageVaultHook.DeletedMessageMailboxContext 
deletedMessageMailboxContext = new 
DeletedMessageVaultHook.DeletedMessageMailboxContext(MESSAGE_ID, EMPTY_OWNER, 
ORIGIN_MAILBOXES);
+        assertThatThrownBy(() -> 
deletedMessageConverter.convert(deletedMessageMailboxContext, 
buildMessage(getMessageBuilder(), ATTACHMENTS), DELETION_DATE))
             .isInstanceOf(NullPointerException.class);
     }
 
@@ -118,7 +115,7 @@ class DeletedMessageConverterTest {
         MessageBuilder builder = getMessageBuilder();
         builder.headers.remove(DATE_FIELD);
 
-        assertThat(deletedMessageConverter.convert(DELETED_MESSAGE_METADATA, 
buildMessage(builder, NO_ATTACHMENT)))
+        
assertThat(deletedMessageConverter.convert(DELETED_MESSAGE_MAILBOX_CONTEXT, 
buildMessage(builder, NO_ATTACHMENT), DELETION_DATE))
             .isEqualTo(DELETED_MESSAGE_WITH_SUBJECT);
     }
 
@@ -127,7 +124,7 @@ class DeletedMessageConverterTest {
         MessageBuilder builder = getMessageBuilder();
         builder.headers.remove(SUBJECT_FIELD);
 
-        assertThat(deletedMessageConverter.convert(DELETED_MESSAGE_METADATA, 
buildMessage(builder, NO_ATTACHMENT)))
+        
assertThat(deletedMessageConverter.convert(DELETED_MESSAGE_MAILBOX_CONTEXT, 
buildMessage(builder, NO_ATTACHMENT), DELETION_DATE))
             .isEqualTo(DELETED_MESSAGE);
     }
 
@@ -135,7 +132,7 @@ class DeletedMessageConverterTest {
     void convertShouldReturnCorrespondingDeletedMessage() throws Exception {
         MessageBuilder builder = getMessageBuilder();
 
-        assertThat(deletedMessageConverter.convert(DELETED_MESSAGE_METADATA, 
buildMessage(builder, NO_ATTACHMENT)))
+        
assertThat(deletedMessageConverter.convert(DELETED_MESSAGE_MAILBOX_CONTEXT, 
buildMessage(builder, NO_ATTACHMENT), DELETION_DATE))
             .isEqualTo(DELETED_MESSAGE_WITH_SUBJECT);
     }
 
@@ -145,7 +142,7 @@ class DeletedMessageConverterTest {
         builder.headers.remove(TO_FIELD);
         builder.headers.remove(CC_FIELD);
 
-        DeletedMessage deletedMessage = 
deletedMessageConverter.convert(DELETED_MESSAGE_METADATA, buildMessage(builder, 
NO_ATTACHMENT));
+        DeletedMessage deletedMessage = 
deletedMessageConverter.convert(DELETED_MESSAGE_MAILBOX_CONTEXT, 
buildMessage(builder, NO_ATTACHMENT), DELETION_DATE);
 
         assertThat(deletedMessage.getRecipients())
             .isEmpty();
@@ -157,7 +154,7 @@ class DeletedMessageConverterTest {
         builder.header(TO_FIELD, "bad@bad@bad");
         builder.header(CC_FIELD, "dad@");
 
-        DeletedMessage deletedMessage = 
deletedMessageConverter.convert(DELETED_MESSAGE_METADATA, buildMessage(builder, 
NO_ATTACHMENT));
+        DeletedMessage deletedMessage = 
deletedMessageConverter.convert(DELETED_MESSAGE_MAILBOX_CONTEXT, 
buildMessage(builder, NO_ATTACHMENT), DELETION_DATE);
         assertThat(deletedMessage.getRecipients())
             .isEmpty();
     }
@@ -167,7 +164,7 @@ class DeletedMessageConverterTest {
         MessageBuilder builder = getMessageBuilder();
         builder.header(TO_FIELD, "bad@bad@bad");
 
-        DeletedMessage deletedMessage = 
deletedMessageConverter.convert(DELETED_MESSAGE_METADATA, buildMessage(builder, 
NO_ATTACHMENT));
+        DeletedMessage deletedMessage = 
deletedMessageConverter.convert(DELETED_MESSAGE_MAILBOX_CONTEXT, 
buildMessage(builder, NO_ATTACHMENT), DELETION_DATE);
         assertThat(deletedMessage.getRecipients())
             .containsOnly(RECIPIENT2);
     }
@@ -177,7 +174,7 @@ class DeletedMessageConverterTest {
         MessageBuilder builder = getMessageBuilder();
         builder.headers.remove(SENDER_FIELD);
 
-        DeletedMessage deletedMessage = 
deletedMessageConverter.convert(DELETED_MESSAGE_METADATA, buildMessage(builder, 
NO_ATTACHMENT));
+        DeletedMessage deletedMessage = 
deletedMessageConverter.convert(DELETED_MESSAGE_MAILBOX_CONTEXT, 
buildMessage(builder, NO_ATTACHMENT), DELETION_DATE);
 
         assertThat(deletedMessage.getSender())
             .isEqualTo(MaybeSender.nullSender());
diff --git 
a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageFixture.java
 
b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageFixture.java
index 612b17b..d2e5c31 100644
--- 
a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageFixture.java
+++ 
b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageFixture.java
@@ -25,6 +25,7 @@ import static 
org.apache.mailet.base.MailAddressFixture.SENDER;
 
 import java.nio.charset.StandardCharsets;
 import java.time.ZonedDateTime;
+import java.util.Date;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
@@ -43,6 +44,7 @@ public interface DeletedMessageFixture {
     User USER_2 = User.fromUsername("[email protected]");
     ZonedDateTime DELIVERY_DATE = ZonedDateTime.parse("2014-10-30T14:12:00Z");
     ZonedDateTime DELETION_DATE = ZonedDateTime.parse("2015-10-30T14:12:00Z");
+    Date INTERNAL_DATE = Date.from(DELIVERY_DATE.toInstant());
     byte[] CONTENT = "header: 
value\r\n\r\ncontent".getBytes(StandardCharsets.UTF_8);
     String SUBJECT = "subject";
 
diff --git 
a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageMetadataTest.java
 
b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageMailboxContextTest.java
similarity index 97%
rename from 
mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageMetadataTest.java
rename to 
mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageMailboxContextTest.java
index caa8271..fa8772b 100644
--- 
a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageMetadataTest.java
+++ 
b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageMailboxContextTest.java
@@ -24,8 +24,7 @@ import org.junit.jupiter.api.Test;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
 
-public class DeletedMessageMetadataTest {
-
+class DeletedMessageMailboxContextTest {
     @Test
     void shouldMatchBeanContract() {
         EqualsVerifier.forClass(PreDeletionHook.DeleteOperation.class)
diff --git 
a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java
 
b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java
new file mode 100644
index 0000000..ff88104
--- /dev/null
+++ 
b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageVaultHookTest.java
@@ -0,0 +1,289 @@
+/****************************************************************
+ * 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.vault;
+
+import static org.apache.james.vault.DeletedMessageFixture.DELETION_DATE;
+import static org.apache.james.vault.DeletedMessageFixture.DELIVERY_DATE;
+import static org.apache.james.vault.DeletedMessageFixture.INTERNAL_DATE;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Clock;
+import java.time.ZoneOffset;
+import java.util.List;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.core.MaybeSender;
+import org.apache.james.core.User;
+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.inmemory.InMemoryMailboxSessionMapperFactory;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.apache.james.mailbox.store.Authenticator;
+import org.apache.james.mailbox.store.Authorizator;
+import org.apache.james.mailbox.store.CombinationManagerTestSystem;
+import org.apache.james.mailbox.store.SessionProvider;
+import org.apache.james.mailbox.store.mail.model.Mailbox;
+import org.apache.james.mime4j.dom.Message;
+import org.apache.james.vault.memory.MemoryDeletedMessagesVault;
+import org.apache.james.vault.search.Query;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+class DeletedMessageVaultHookTest {
+
+    private static final String ALICE_ADDRESS = "[email protected]";
+    private static final String BOB_ADDRESS = "[email protected]";
+    private static final String TEST_ADDRESS = "[email protected]";
+    private static final User ALICE = User.fromUsername(ALICE_ADDRESS);
+    private static final User BOB = User.fromUsername(BOB_ADDRESS);
+
+    private static final MailboxPath MAILBOX_ALICE_ONE = 
MailboxPath.forUser(ALICE_ADDRESS, "ALICE_ONE");
+    private static final MailboxPath MAILBOX_BOB_ONE = 
MailboxPath.forUser(BOB_ADDRESS, "BOB_ONE");
+
+    private MailboxManager mailboxManager;
+    private MessageIdManager messageIdManager;
+    private Message mailContent;
+    private MemoryDeletedMessagesVault messageVault;
+    private Clock clock;
+    private SessionProvider sessionProvider;
+    private MailboxSession aliceSession;
+    private MailboxSession bobSession;
+    private InMemoryMailboxSessionMapperFactory mapperFactory;
+    private CombinationManagerTestSystem testingData;
+    private SearchQuery searchQuery;
+
+    private DeletedMessage buildDeletedMessage(List<MailboxId> mailboxIds, 
MessageId messageId, User user) throws Exception {
+        return DeletedMessage.builder()
+            .messageId(messageId)
+            .originMailboxes(mailboxIds)
+            .user(user)
+            .deliveryDate(DELIVERY_DATE)
+            .deletionDate(DELETION_DATE)
+            .sender(MaybeSender.getMailSender(ALICE_ADDRESS))
+            .recipients(new MailAddress(TEST_ADDRESS))
+            .hasAttachment(false)
+            .subject("test")
+            .build();
+    }
+
+    private ComposedMessageId appendMessage(MessageManager messageManager) 
throws Exception {
+        return 
messageManager.appendMessage(MessageManager.AppendCommand.builder()
+                .withInternalDate(INTERNAL_DATE)
+                .build(mailContent), aliceSession);
+    }
+
+    @BeforeEach
+    void setUp() throws Exception {
+        clock = Clock.fixed(DELETION_DATE.toInstant(), ZoneOffset.UTC);
+        messageVault = new MemoryDeletedMessagesVault();
+
+        Authenticator noAuthenticator = null;
+        Authorizator noAuthorizator = null;
+        sessionProvider = new SessionProvider(noAuthenticator, noAuthorizator);
+        aliceSession = sessionProvider.createSystemSession(ALICE_ADDRESS);
+        bobSession = sessionProvider.createSystemSession(BOB_ADDRESS);
+
+        mapperFactory = new InMemoryMailboxSessionMapperFactory();
+        DeletedMessageConverter deletedMessageConverter = new 
DeletedMessageConverter();
+        DeletedMessageVaultHook messageVaultHook = new 
DeletedMessageVaultHook(sessionProvider, messageVault, deletedMessageConverter, 
mapperFactory, clock);
+
+        testingData = MessageIdManagerWithPreDeletionHooksTestSystemProvider
+            .createTestingData(sessionProvider, mapperFactory, 
ImmutableSet.of(messageVaultHook));
+
+        mailboxManager = testingData.getMailboxManager();
+        messageIdManager = testingData.getMessageIdManager();
+
+        mailContent = Message.Builder.of()
+            .setSubject("test")
+            .setBody("testmail", StandardCharsets.UTF_8)
+            .setSender(ALICE_ADDRESS)
+            .setTo(TEST_ADDRESS)
+            .setDate(INTERNAL_DATE)
+            .build();
+
+        searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.internalDateOn(INTERNAL_DATE, 
SearchQuery.DateResolution.Second));
+    }
+
+    @Test
+    void notifyDeleteShouldAppendMessageVault() throws Exception {
+        Mailbox aliceMailbox = testingData.createMailbox(MAILBOX_ALICE_ONE, 
aliceSession);
+        MessageManager messageManager = 
testingData.createMessageManager(aliceMailbox, aliceSession);
+        MessageId messageId = appendMessage(messageManager).getMessageId();
+
+        messageIdManager.delete(ImmutableList.of(messageId), aliceSession);
+
+        DeletedMessage deletedMessage = 
buildDeletedMessage(ImmutableList.of(aliceMailbox.getMailboxId()), messageId, 
ALICE);
+        assertThat(messageVault.search(ALICE, Query.ALL).blockFirst())
+            .isEqualTo(deletedMessage);
+    }
+
+    @Test
+    void 
notifyDeleteShouldAppendMessageToVaultOfMailboxOwnerWhenOtherUserDeleteMessageInSharingMailbox()
 throws Exception {
+        Mailbox aliceMailbox = testingData.createMailbox(MAILBOX_ALICE_ONE, 
aliceSession);
+        MessageManager aliceMessageManager = 
testingData.createMessageManager(aliceMailbox, aliceSession);
+        MessageManager bobMessageManager = 
testingData.createMessageManager(aliceMailbox, bobSession);
+        ComposedMessageId composedMessageId = 
appendMessage(aliceMessageManager);
+        MessageId messageId = composedMessageId.getMessageId();
+
+        mailboxManager.setRights(MAILBOX_ALICE_ONE,
+            MailboxACL.EMPTY.apply(MailboxACL.command()
+                .forUser(BOB_ADDRESS)
+                .rights(MailboxACL.Right.Lookup, MailboxACL.Right.Read, 
MailboxACL.Right.DeleteMessages, MailboxACL.Right.PerformExpunge)
+                .asAddition()),
+            aliceSession);
+
+        DeletedMessage deletedMessage = 
buildDeletedMessage(ImmutableList.of(aliceMailbox.getMailboxId()), messageId, 
ALICE);
+        
bobMessageManager.delete(ImmutableList.copyOf(bobMessageManager.search(searchQuery,
 bobSession)), bobSession);
+
+        assertThat(messageVault.search(ALICE, Query.ALL).blockFirst())
+            .isEqualTo(deletedMessage);
+    }
+
+    @Test
+    void 
notifyDeleteShouldNotAppendMessageToVaultOfOtherUserOfMailboxWhenOtherUserDeleteMessageInSharingMailbox()
 throws Exception {
+        Mailbox aliceMailbox = testingData.createMailbox(MAILBOX_ALICE_ONE, 
aliceSession);
+        MessageManager aliceMessageManager = 
testingData.createMessageManager(aliceMailbox, aliceSession);
+        MessageManager bobMessageManager = 
testingData.createMessageManager(aliceMailbox, bobSession);
+        appendMessage(aliceMessageManager);
+
+        mailboxManager.setRights(MAILBOX_ALICE_ONE,
+            MailboxACL.EMPTY.apply(MailboxACL.command()
+                .forUser(BOB_ADDRESS)
+                .rights(MailboxACL.Right.Lookup, MailboxACL.Right.Read, 
MailboxACL.Right.DeleteMessages, MailboxACL.Right.PerformExpunge)
+                .asAddition()),
+            aliceSession);
+
+        
bobMessageManager.delete(ImmutableList.copyOf(bobMessageManager.search(searchQuery,
 bobSession)), bobSession);
+
+        assertThat(messageVault.search(BOB, Query.ALL).collectList().block())
+            .isEmpty();
+    }
+
+    @Test
+    void 
notifyDeleteShouldAppendMessageToVaultOfOtherUserOfMailboxWhenOtherUserDeleteMessageAfterMoveToAnotherMailbox()
 throws Exception {
+        Mailbox aliceMailbox = testingData.createMailbox(MAILBOX_ALICE_ONE, 
aliceSession);
+        Mailbox bobMailbox = testingData.createMailbox(MAILBOX_BOB_ONE, 
bobSession);
+        MessageManager aliceMessageManager = 
testingData.createMessageManager(aliceMailbox, aliceSession);
+        MessageManager bobMessageManager = 
testingData.createMessageManager(bobMailbox, bobSession);
+        ComposedMessageId composedMessageId = 
appendMessage(aliceMessageManager);
+        MessageId messageId = composedMessageId.getMessageId();
+
+        mailboxManager.setRights(MAILBOX_ALICE_ONE,
+            MailboxACL.EMPTY.apply(MailboxACL.command()
+                .forUser(BOB_ADDRESS)
+                .rights(MailboxACL.Right.Lookup, MailboxACL.Right.Read, 
MailboxACL.Right.DeleteMessages, MailboxACL.Right.PerformExpunge)
+                .asAddition()),
+            aliceSession);
+
+        messageIdManager.setInMailboxes(messageId, 
ImmutableList.of(bobMailbox.getMailboxId()), bobSession);
+
+        DeletedMessage deletedMessage = 
buildDeletedMessage(ImmutableList.of(bobMailbox.getMailboxId()), messageId, 
BOB);
+        
bobMessageManager.delete(ImmutableList.copyOf(bobMessageManager.search(searchQuery,
 bobSession)), bobSession);
+
+        assertThat(messageVault.search(BOB, Query.ALL).blockFirst())
+            .isEqualTo(deletedMessage);
+    }
+
+    @Test
+    void 
notifyDeleteShouldNotAppendMessageToVaultOfMailboxOwnerWhenOtherUserDeleteMessageAfterMoveToAnotherMailbox()
 throws Exception {
+        Mailbox aliceMailbox = testingData.createMailbox(MAILBOX_ALICE_ONE, 
aliceSession);
+        Mailbox bobMailbox = testingData.createMailbox(MAILBOX_BOB_ONE, 
bobSession);
+        MessageManager aliceMessageManager = 
testingData.createMessageManager(aliceMailbox, aliceSession);
+        MessageManager bobMessageManager = 
testingData.createMessageManager(bobMailbox, bobSession);
+        ComposedMessageId composedMessageId = 
appendMessage(aliceMessageManager);
+        MessageId messageId = composedMessageId.getMessageId();
+
+        mailboxManager.setRights(MAILBOX_ALICE_ONE,
+            MailboxACL.EMPTY.apply(MailboxACL.command()
+                .forUser(BOB_ADDRESS)
+                .rights(MailboxACL.Right.Lookup, MailboxACL.Right.Read, 
MailboxACL.Right.DeleteMessages, MailboxACL.Right.PerformExpunge)
+                .asAddition()),
+            aliceSession);
+
+        messageIdManager.setInMailboxes(messageId, 
ImmutableList.of(bobMailbox.getMailboxId()), bobSession);
+
+        
bobMessageManager.delete(ImmutableList.copyOf(bobMessageManager.search(searchQuery,
 bobSession)), bobSession);
+
+        assertThat(messageVault.search(ALICE, Query.ALL).collectList().block())
+            .isEmpty();
+    }
+
+    @Test
+    void 
notifyDeleteShouldAppendMessageToVaultOfOtherUserOfMailboxWhenOtherUserDeleteMessageAfterCopyToAnotherMailbox()
 throws Exception {
+        Mailbox aliceMailbox = testingData.createMailbox(MAILBOX_ALICE_ONE, 
aliceSession);
+        Mailbox bobMailbox = testingData.createMailbox(MAILBOX_BOB_ONE, 
bobSession);
+        MessageManager aliceMessageManager = 
testingData.createMessageManager(aliceMailbox, aliceSession);
+        MessageManager bobMessageManager = 
testingData.createMessageManager(bobMailbox, bobSession);
+        ComposedMessageId composedMessageId = 
appendMessage(aliceMessageManager);
+        MessageId messageId = composedMessageId.getMessageId();
+
+        mailboxManager.setRights(MAILBOX_ALICE_ONE,
+            MailboxACL.EMPTY.apply(MailboxACL.command()
+                .forUser(BOB_ADDRESS)
+                .rights(MailboxACL.Right.Lookup, MailboxACL.Right.Read, 
MailboxACL.Right.DeleteMessages, MailboxACL.Right.PerformExpunge)
+                .asAddition()),
+            aliceSession);
+
+        messageIdManager.setInMailboxes(messageId, 
ImmutableList.of(aliceMailbox.getMailboxId(), bobMailbox.getMailboxId()), 
bobSession);
+
+        DeletedMessage deletedMessage = 
buildDeletedMessage(ImmutableList.of(bobMailbox.getMailboxId()), messageId, 
BOB);
+        
bobMessageManager.delete(ImmutableList.copyOf(bobMessageManager.search(searchQuery,
 bobSession)), bobSession);
+
+        assertThat(messageVault.search(BOB, Query.ALL).blockFirst())
+            .isEqualTo(deletedMessage);
+    }
+
+    @Test
+    void 
notifyDeleteShouldNotAppendMessageToVaultOfMailboxOwnerWhenOtherUserDeleteMessageAfterCopyToAnotherMailbox()
 throws Exception {
+        Mailbox aliceMailbox = testingData.createMailbox(MAILBOX_ALICE_ONE, 
aliceSession);
+        Mailbox bobMailbox = testingData.createMailbox(MAILBOX_BOB_ONE, 
bobSession);
+        MessageManager aliceMessageManager = 
testingData.createMessageManager(aliceMailbox, aliceSession);
+        MessageManager bobMessageManager = 
testingData.createMessageManager(bobMailbox, bobSession);
+        ComposedMessageId composedMessageId = 
appendMessage(aliceMessageManager);
+        MessageId messageId = composedMessageId.getMessageId();
+
+        mailboxManager.setRights(MAILBOX_ALICE_ONE,
+            MailboxACL.EMPTY.apply(MailboxACL.command()
+                .forUser(BOB_ADDRESS)
+                .rights(MailboxACL.Right.Lookup, MailboxACL.Right.Read, 
MailboxACL.Right.DeleteMessages, MailboxACL.Right.PerformExpunge)
+                .asAddition()),
+            aliceSession);
+
+        messageIdManager.setInMailboxes(messageId, 
ImmutableList.of(aliceMailbox.getMailboxId(), bobMailbox.getMailboxId()), 
bobSession);
+
+        
bobMessageManager.delete(ImmutableList.copyOf(bobMessageManager.search(searchQuery,
 bobSession)), bobSession);
+
+        assertThat(messageVault.search(ALICE, Query.ALL).collectList().block())
+            .isEmpty();
+    }
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to