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 d2c5ca54f57baca2848266f6db37777d8e1208b5
Author: tran tien duc <[email protected]>
AuthorDate: Wed Feb 20 18:15:52 2019 +0700

    MAILBOX-379 Plug PreDeletionHook to MailboxStoreManager
    
    - Implement hook tests and enable them for Memory & Cassandra tests
    - Disable hook tests for Maildir, JPA mailbox managers, because feature
    seems like be not supported, when running hook tests I saw DefaultMessageId
    doesn't support equals method which is used in hook tests.
    - Disable temporally Memory hook tests, I see a messy setup for Memory
    mailbox system, it hard to inject hooks to tested instance. Will address
    it in next commits
---
 .../apache/james/mailbox/MailboxManagerTest.java   | 172 +++++++++++++++++++++
 .../mailbox/cassandra/CassandraMailboxManager.java |  11 +-
 .../mailbox/cassandra/CassandraMessageManager.java |   8 +-
 .../cassandra/CassandraMailboxManagerProvider.java |   8 +-
 .../CassandraMailboxManagerStressTest.java         |   3 +-
 .../cassandra/CassandraMailboxManagerTest.java     |   3 +-
 .../cassandra/CassandraTestSystemFixture.java      |   2 +-
 .../CassandraMailboxManagerAttachmentTest.java     |   5 +-
 .../ElasticSearchIntegrationTest.java              |   3 +-
 .../james/mailbox/jpa/JPAMailboxManager.java       |   3 +-
 .../james/mailbox/jpa/JPAMessageManager.java       |   3 +-
 .../james/mailbox/jpa/JPAMailboxManagerTest.java   |   7 +
 .../search/LuceneMessageSearchIndexTest.java       |   3 +-
 .../DomainUserMaildirMailboxManagerTest.java       |  10 ++
 .../maildir/FullUserMaildirMailboxManagerTest.java |   9 ++
 .../maildir/MaildirMailboxManagerProvider.java     |   3 +-
 .../mailbox/inmemory/InMemoryMailboxManager.java   |   8 +-
 .../mailbox/inmemory/InMemoryMessageManager.java   |   3 +-
 .../mailbox/inmemory/MemoryMailboxManagerTest.java |   8 +
 .../mail/InMemoryMailboxManagerAttachmentTest.java |   5 +-
 .../manager/InMemoryIntegrationResources.java      |   3 +-
 .../InMemoryMessageIdManagerSideEffectTest.java    |   3 +-
 .../james/mailbox/store/StoreMailboxManager.java   |  12 +-
 .../james/mailbox/store/StoreMessageManager.java   |  34 +++-
 .../mailbox/store/StoreMailboxManagerTest.java     |   3 +-
 .../tools/indexer/CassandraReIndexerImplTest.java  |   4 +-
 .../cassandra/host/CassandraHostSystem.java        |   3 +-
 .../host/ElasticSearchHostSystem.java              |   4 +-
 .../lucenesearch/host/LuceneSearchHostSystem.java  |   4 +-
 .../maildir/host/MaildirHostSystem.java            |   3 +-
 30 files changed, 317 insertions(+), 33 deletions(-)

diff --git 
a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java 
b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index db11402..ae6e3c9 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -23,11 +23,18 @@ import static 
org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.assertj.core.api.SoftAssertions.assertSoftly;
 import static org.junit.jupiter.api.Assumptions.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import java.nio.charset.StandardCharsets;
 import java.time.Duration;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
 
 import javax.mail.Flags;
 
@@ -42,8 +49,10 @@ import org.apache.james.mailbox.events.MessageMoveEvent;
 import org.apache.james.mailbox.exception.AnnotationException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.TooLongMailboxNameException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.mock.DataProvisioner;
 import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.FetchGroupImpl;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxAnnotation;
 import org.apache.james.mailbox.model.MailboxAnnotationKey;
@@ -53,6 +62,7 @@ import org.apache.james.mailbox.model.MailboxMetaData;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.model.MessageResult;
 import org.apache.james.mailbox.model.MultimailboxesSearchQuery;
 import org.apache.james.mailbox.model.Quota;
 import org.apache.james.mailbox.model.QuotaRoot;
@@ -61,15 +71,19 @@ import org.apache.james.mailbox.model.search.MailboxQuery;
 import org.apache.james.mailbox.util.EventCollector;
 import org.apache.james.mime4j.dom.Message;
 import org.apache.james.util.concurrency.ConcurrentTestRunner;
+import org.assertj.core.api.SoftAssertions;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
 
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
+import reactor.core.publisher.Mono;
+
 /**
  * Test the {@link MailboxManager} methods that
  * are not covered by the protocol-tester suite.
@@ -88,12 +102,20 @@ public abstract class MailboxManagerTest<T extends 
MailboxManager> {
     private MailboxSession session;
     private Message.Builder message;
 
+    private PreDeletionHook preDeletionHook1;
+    private PreDeletionHook preDeletionHook2;
+
     protected abstract T provideMailboxManager();
 
     protected abstract EventBus retrieveEventBus(T mailboxManager);
 
+    protected Set<PreDeletionHook> preDeletionHooks() {
+        return ImmutableSet.of(preDeletionHook1, preDeletionHook2);
+    }
+
     @BeforeEach
     void setUp() throws Exception {
+        setupMockForPreDeletionHooks();
         this.mailboxManager = provideMailboxManager();
 
         this.message = Message.Builder.of()
@@ -101,6 +123,16 @@ public abstract class MailboxManagerTest<T extends 
MailboxManager> {
             .setBody("testmail", StandardCharsets.UTF_8);
     }
 
+    private void setupMockForPreDeletionHooks() {
+        preDeletionHook1 = mock(PreDeletionHook.class);
+        
when(preDeletionHook1.notifyDelete(any(PreDeletionHook.DeleteOperation.class)))
+            .thenReturn(Mono.empty());
+
+        preDeletionHook2 = mock(PreDeletionHook.class);
+        
when(preDeletionHook2.notifyDelete(any(PreDeletionHook.DeleteOperation.class)))
+            .thenReturn(Mono.empty());
+    }
+
     @AfterEach
     void tearDown() throws Exception {
         mailboxManager.logout(session, false);
@@ -1300,4 +1332,144 @@ public abstract class MailboxManagerTest<T extends 
MailboxManager> {
             assertThat(session.isOpen()).isFalse();
         }
     }
+
+    @Nested
+    class HookTests {
+
+        @Nested
+        class PreDeletion {
+
+            private final QuotaRoot quotaRoot = 
QuotaRoot.quotaRoot("#private&USER_1", Optional.empty());
+            private MailboxPath inbox;
+            private MailboxId inboxId;
+            private MailboxId anotherMailboxId;
+            private MessageManager inboxManager;
+            private MessageManager anotherMailboxManager;
+
+            @BeforeEach
+            void setUp() throws Exception {
+                session = mailboxManager.createSystemSession(USER_1);
+                inbox = MailboxPath.inbox(session);
+
+                MailboxPath anotherMailboxPath = MailboxPath.forUser(USER_1, 
"anotherMailbox");
+                anotherMailboxId = 
mailboxManager.createMailbox(anotherMailboxPath, session).get();
+
+                inboxId = mailboxManager.createMailbox(inbox, session).get();
+                inboxManager = mailboxManager.getMailbox(inbox, session);
+                anotherMailboxManager = 
mailboxManager.getMailbox(anotherMailboxPath, session);
+            }
+
+            @Test
+            void expungeShouldCallAllPreDeletionHooks() throws Exception {
+                ComposedMessageId composeId = 
inboxManager.appendMessage(AppendCommand.builder()
+                    .build(message), session);
+                inboxManager.expunge(MessageRange.one(composeId.getUid()), 
session);
+
+                ArgumentCaptor<PreDeletionHook.DeleteOperation> 
preDeleteCaptor1 = 
ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
+                ArgumentCaptor<PreDeletionHook.DeleteOperation> 
preDeleteCaptor2 = 
ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
+                verify(preDeletionHook1, 
times(1)).notifyDelete(preDeleteCaptor1.capture());
+                verify(preDeletionHook2, 
times(1)).notifyDelete(preDeleteCaptor2.capture());
+
+                
assertThat(preDeleteCaptor1.getValue().getDeletionMetadataList())
+                    .hasSize(1)
+                    
.hasSameElementsAs(preDeleteCaptor2.getValue().getDeletionMetadataList())
+                    .allSatisfy(deleteMetadata -> 
SoftAssertions.assertSoftly(softy -> {
+                        
softy.assertThat(deleteMetadata.getMailboxId()).isEqualTo(inboxId);
+                        
softy.assertThat(deleteMetadata.getMessageMetaData().getMessageId()).isEqualTo(composeId.getMessageId());
+                    }));
+            }
+
+            @Test
+            void 
expungeShouldCallAllPreDeletionHooksOnEachMessageDeletionCall() throws 
Exception {
+                ComposedMessageId composeId1 = 
inboxManager.appendMessage(AppendCommand.builder().build(message), session);
+                ComposedMessageId composeId2 = 
inboxManager.appendMessage(AppendCommand.builder().build(message), session);
+
+                inboxManager.expunge(MessageRange.one(composeId1.getUid()), 
session);
+                inboxManager.expunge(MessageRange.one(composeId2.getUid()), 
session);
+
+                ArgumentCaptor<PreDeletionHook.DeleteOperation> 
preDeleteCaptor1 = 
ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
+                ArgumentCaptor<PreDeletionHook.DeleteOperation> 
preDeleteCaptor2 = 
ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
+                verify(preDeletionHook1, 
times(2)).notifyDelete(preDeleteCaptor1.capture());
+                verify(preDeletionHook2, 
times(2)).notifyDelete(preDeleteCaptor2.capture());
+
+                assertThat(preDeleteCaptor1.getAllValues())
+                    .hasSize(2)
+                    .hasSameElementsAs(preDeleteCaptor2.getAllValues())
+                    
.flatExtracting(PreDeletionHook.DeleteOperation::getDeletionMetadataList)
+                    .allSatisfy(deleteMetadata -> 
assertThat(deleteMetadata.getMailboxId()).isEqualTo(inboxId))
+                    .extracting(deleteMetadata -> 
deleteMetadata.getMessageMetaData().getMessageId())
+                    .containsOnly(composeId1.getMessageId(), 
composeId2.getMessageId());
+            }
+
+            @Test
+            void 
expungeShouldCallAllPreDeletionHooksOnEachMessageDeletionOnDifferentMailboxes() 
throws Exception {
+                ComposedMessageId composeId1 = 
inboxManager.appendMessage(AppendCommand.builder().build(message), session);
+                ComposedMessageId composeId2 = 
anotherMailboxManager.appendMessage(AppendCommand.builder().build(message), 
session);
+
+                inboxManager.expunge(MessageRange.one(composeId1.getUid()), 
session);
+                
anotherMailboxManager.expunge(MessageRange.one(composeId2.getUid()), session);
+
+                ArgumentCaptor<PreDeletionHook.DeleteOperation> 
preDeleteCaptor1 = 
ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
+                ArgumentCaptor<PreDeletionHook.DeleteOperation> 
preDeleteCaptor2 = 
ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
+                verify(preDeletionHook1, 
times(2)).notifyDelete(preDeleteCaptor1.capture());
+                verify(preDeletionHook2, 
times(2)).notifyDelete(preDeleteCaptor2.capture());
+
+                assertThat(preDeleteCaptor1.getAllValues())
+                    .hasSameElementsAs(preDeleteCaptor2.getAllValues())
+                    
.flatExtracting(PreDeletionHook.DeleteOperation::getDeletionMetadataList)
+                    .extracting(deleteMetadata -> 
deleteMetadata.getMessageMetaData().getMessageId())
+                    .containsOnly(composeId1.getMessageId(), 
composeId2.getMessageId());
+
+                assertThat(preDeleteCaptor1.getAllValues())
+                    .hasSameElementsAs(preDeleteCaptor2.getAllValues())
+                    
.flatExtracting(PreDeletionHook.DeleteOperation::getDeletionMetadataList)
+                    .extracting(MetadataWithMailboxId::getMailboxId)
+                    .containsOnly(inboxId, anotherMailboxId);
+            }
+
+            @Test
+            void expungeShouldNotBeExecutedWhenOneOfPreDeleteHooksFails() 
throws Exception {
+                
when(preDeletionHook1.notifyDelete(any(PreDeletionHook.DeleteOperation.class)))
+                    .thenThrow(new RuntimeException("throw at hook 1"));
+
+                ComposedMessageId composeId1 = 
inboxManager.appendMessage(AppendCommand.builder().build(message), session);
+                assertThatThrownBy(() -> 
inboxManager.expunge(MessageRange.one(composeId1.getUid()), session))
+                    .isInstanceOf(RuntimeException.class);
+
+                
assertThat(ImmutableList.copyOf(inboxManager.getMessages(MessageRange.one(composeId1.getUid()),
 FetchGroupImpl.MINIMAL, session))
+                        .stream()
+                        .map(MessageResult::getMessageId))
+                    .hasSize(1)
+                    .containsOnly(composeId1.getMessageId());
+            }
+
+            @Test
+            void expungeShouldBeExecutedAfterAllHooksFinish() throws Exception 
{
+                CountDownLatch latchForHook1 = new CountDownLatch(1);
+                
when(preDeletionHook1.notifyDelete(any(PreDeletionHook.DeleteOperation.class)))
+                    .thenAnswer(invocation -> {
+                        latchForHook1.countDown();
+                        return Mono.empty();
+                    });
+
+                CountDownLatch latchForHook2 = new CountDownLatch(1);
+                
when(preDeletionHook2.notifyDelete(any(PreDeletionHook.DeleteOperation.class)))
+                    .thenAnswer(invocation -> {
+                        latchForHook2.countDown();
+                        return Mono.empty();
+                    });
+
+                ComposedMessageId composeId1 = 
inboxManager.appendMessage(AppendCommand.builder().build(message), session);
+                inboxManager.setFlags(new Flags(Flags.Flag.DELETED), 
MessageManager.FlagsUpdateMode.ADD,
+                    MessageRange.one(composeId1.getUid()), session);
+                inboxManager.expunge(MessageRange.all(), session);
+
+                latchForHook1.await();
+                latchForHook2.await();
+
+                
assertThat(inboxManager.getMessages(MessageRange.one(composeId1.getUid()), 
FetchGroupImpl.MINIMAL, session))
+                    .isEmpty();
+            }
+        }
+    }
 }
diff --git 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
index 44a00ad..e1b4442 100644
--- 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
+++ 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
@@ -20,6 +20,7 @@
 package org.apache.james.mailbox.cassandra;
 
 import java.util.EnumSet;
+import java.util.Set;
 
 import javax.inject.Inject;
 
@@ -27,6 +28,7 @@ import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.events.EventBus;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageId;
@@ -64,7 +66,8 @@ public class CassandraMailboxManager extends 
StoreMailboxManager {
                                    MessageId.Factory messageIdFactory, 
EventBus eventBus,
                                    StoreMailboxAnnotationManager 
annotationManager, StoreRightManager storeRightManager,
                                    QuotaComponents quotaComponents, 
MessageSearchIndex index,
-                                   MailboxManagerConfiguration configuration) {
+                                   MailboxManagerConfiguration configuration,
+                                   Set<PreDeletionHook> preDeletionHooks) {
         super(mapperFactory,
             sessionProvider,
             locker,
@@ -75,7 +78,8 @@ public class CassandraMailboxManager extends 
StoreMailboxManager {
             storeRightManager,
             quotaComponents,
             index,
-            configuration);
+            configuration,
+            preDeletionHooks);
         this.locker = locker;
         this.mapperFactory = mapperFactory;
     }
@@ -109,7 +113,8 @@ public class CassandraMailboxManager extends 
StoreMailboxManager {
             getMessageParser(),
             getMessageIdFactory(),
             configuration.getBatchSizes(),
-            getStoreRightManager());
+            getStoreRightManager(),
+            getPreDeletionHooks());
     }
 
 }
diff --git 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
index 918dd1d..29114a4 100644
--- 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
+++ 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
@@ -20,6 +20,7 @@
 package org.apache.james.mailbox.cassandra;
 
 import java.util.List;
+import java.util.Set;
 
 import javax.mail.Flags;
 
@@ -27,6 +28,7 @@ import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.quota.QuotaManager;
@@ -53,9 +55,11 @@ public class CassandraMessageManager extends 
StoreMessageManager {
                             EventBus eventBus, MailboxPathLocker locker, 
Mailbox mailbox, QuotaManager quotaManager,
                             QuotaRootResolver quotaRootResolver, MessageParser 
messageParser, MessageId.Factory messageIdFactory,
                             BatchSizes batchSizes,
-                            StoreRightManager storeRightManager) {
+                            StoreRightManager storeRightManager,
+                            Set<PreDeletionHook> preDeletionHooks) {
         super(CassandraMailboxManager.MESSAGE_CAPABILITIES, mapperFactory, 
index, eventBus, locker, mailbox,
-            quotaManager, quotaRootResolver, messageParser, messageIdFactory, 
batchSizes, storeRightManager);
+            quotaManager, quotaRootResolver, messageParser, messageIdFactory, 
batchSizes, storeRightManager,
+            preDeletionHooks);
 
         this.mapperFactory = mapperFactory;
     }
diff --git 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
index 5849e2f..cdfe721 100644
--- 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
+++ 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
@@ -19,6 +19,8 @@
 
 package org.apache.james.mailbox.cassandra;
 
+import java.util.Set;
+
 import org.apache.james.backends.cassandra.init.CassandraTypesProvider;
 import org.apache.james.mailbox.acl.GroupMembershipResolver;
 import org.apache.james.mailbox.acl.MailboxACLResolver;
@@ -32,6 +34,7 @@ import 
org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaDao;
 import 
org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaManager;
 import org.apache.james.mailbox.events.InVMEventBus;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.quota.QuotaRootResolver;
 import org.apache.james.mailbox.store.Authenticator;
 import org.apache.james.mailbox.store.Authorizator;
@@ -57,7 +60,8 @@ public class CassandraMailboxManagerProvider {
     private static final int LIMIT_ANNOTATIONS = 3;
     private static final int LIMIT_ANNOTATION_SIZE = 30;
 
-    public static CassandraMailboxManager provideMailboxManager(Session 
session, CassandraTypesProvider cassandraTypesProvider) {
+    public static CassandraMailboxManager provideMailboxManager(Session 
session, CassandraTypesProvider cassandraTypesProvider,
+                                                                
Set<PreDeletionHook> preDeletionHooks) {
         CassandraMessageId.Factory messageIdFactory = new 
CassandraMessageId.Factory();
 
         CassandraMailboxSessionMapperFactory mapperFactory = 
TestCassandraMailboxSessionMapperFactory.forTests(
@@ -90,7 +94,7 @@ public class CassandraMailboxManagerProvider {
 
         CassandraMailboxManager manager = new 
CassandraMailboxManager(mapperFactory, sessionProvider, new 
NoMailboxPathLocker(),
             messageParser, messageIdFactory, eventBus, annotationManager, 
storeRightManager,
-            quotaComponents, index, MailboxManagerConfiguration.DEFAULT);
+            quotaComponents, index, MailboxManagerConfiguration.DEFAULT, 
preDeletionHooks);
 
         eventBus.register(quotaUpdater);
         eventBus.register(new MailboxAnnotationListener(mapperFactory, 
sessionProvider));
diff --git 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java
 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java
index 94d3092..4569fbd 100644
--- 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java
+++ 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java
@@ -24,6 +24,7 @@ import 
org.apache.james.backends.cassandra.DockerCassandraRule;
 import org.apache.james.mailbox.MailboxManagerStressTest;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
 import org.apache.james.mailbox.events.EventBus;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
@@ -48,7 +49,7 @@ public class CassandraMailboxManagerStressTest extends 
MailboxManagerStressTest<
     
     @Override
     protected CassandraMailboxManager provideManager() {
-        return 
CassandraMailboxManagerProvider.provideMailboxManager(cassandra.getConf(), 
cassandra.getTypesProvider());
+        return 
CassandraMailboxManagerProvider.provideMailboxManager(cassandra.getConf(), 
cassandra.getTypesProvider(), PreDeletionHook.NO_PRE_DELETION_HOOK);
     }
 
     @Override
diff --git 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
index 0408aa6..cb24d0e 100644
--- 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
+++ 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
@@ -32,7 +32,8 @@ public class CassandraMailboxManagerTest extends 
MailboxManagerTest<CassandraMai
     protected CassandraMailboxManager provideMailboxManager() {
         return CassandraMailboxManagerProvider.provideMailboxManager(
             cassandra.getCassandraCluster().getConf(),
-            cassandra.getCassandraCluster().getTypesProvider());
+            cassandra.getCassandraCluster().getTypesProvider(),
+            preDeletionHooks());
     }
 
     @Override
diff --git 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
index 4c32722..aafe425 100644
--- 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
+++ 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
@@ -78,7 +78,7 @@ class CassandraTestSystemFixture {
         MessageSearchIndex index = new SimpleMessageSearchIndex(mapperFactory, 
mapperFactory, new DefaultTextExtractor());
         CassandraMailboxManager cassandraMailboxManager = new 
CassandraMailboxManager(mapperFactory, sessionProvider,
             new NoMailboxPathLocker(), new MessageParser(), new 
CassandraMessageId.Factory(),
-            eventBus, annotationManager, storeRightManager, quotaComponents, 
index, MailboxManagerConfiguration.DEFAULT);
+            eventBus, annotationManager, storeRightManager, quotaComponents, 
index, MailboxManagerConfiguration.DEFAULT, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
 
         eventBus.register(new MailboxAnnotationListener(mapperFactory, 
sessionProvider));
 
diff --git 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
index d0ff808..23c9bb0 100644
--- 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
+++ 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
@@ -33,6 +33,7 @@ import 
org.apache.james.mailbox.cassandra.TestCassandraMailboxSessionMapperFacto
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.events.InVMEventBus;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.store.AbstractMailboxManagerAttachmentTest;
 import org.apache.james.mailbox.store.Authenticator;
 import org.apache.james.mailbox.store.Authorizator;
@@ -104,13 +105,13 @@ public class CassandraMailboxManagerAttachmentTest 
extends AbstractMailboxManage
 
         mailboxManager = new 
CassandraMailboxManager(mailboxSessionMapperFactory, sessionProvider, new 
NoMailboxPathLocker(), new MessageParser(),
             messageIdFactory, eventBus, annotationManager, storeRightManager, 
quotaComponents,
-            index, MailboxManagerConfiguration.DEFAULT);
+            index, MailboxManagerConfiguration.DEFAULT, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
         MessageParser failingMessageParser = mock(MessageParser.class);
         when(failingMessageParser.retrieveAttachments(any()))
             .thenThrow(new RuntimeException("Message parser set to fail"));
         parseFailingMailboxManager = new 
CassandraMailboxManager(mailboxSessionMapperFactory, sessionProvider,
             new NoMailboxPathLocker(), failingMessageParser, messageIdFactory,
-            eventBus, annotationManager, storeRightManager, quotaComponents, 
index, MailboxManagerConfiguration.DEFAULT);
+            eventBus, annotationManager, storeRightManager, quotaComponents, 
index, MailboxManagerConfiguration.DEFAULT, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
     }
 
     @Override
diff --git 
a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
 
b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
index e49c063..0d1037a 100644
--- 
a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
+++ 
b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
@@ -152,7 +152,8 @@ public class ElasticSearchIntegrationTest extends 
AbstractMessageSearchIndexTest
             annotationManager,
             storeRightManager,
             quotaComponents,
-            elasticSearchListeningMessageSearchIndex);
+            elasticSearchListeningMessageSearchIndex,
+            PreDeletionHook.NO_PRE_DELETION_HOOK);
 
         messageIdManager = new StoreMessageIdManager(
             storeMailboxManager,
diff --git 
a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMailboxManager.java 
b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMailboxManager.java
index 86ae50f..b0240d5 100644
--- 
a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMailboxManager.java
+++ 
b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMailboxManager.java
@@ -24,6 +24,7 @@ import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.jpa.mail.JPAMailboxMapper;
 import org.apache.james.mailbox.jpa.mail.model.JPAMailbox;
 import org.apache.james.mailbox.model.MailboxPath;
@@ -62,7 +63,7 @@ public abstract class JPAMailboxManager extends 
StoreMailboxManager {
         super(mailboxSessionMapperFactory, sessionProvider, locker,
             messageParser, messageIdFactory, annotationManager,
             eventBus, storeRightManager, quotaComponents,
-            index, MailboxManagerConfiguration.DEFAULT);
+            index, MailboxManagerConfiguration.DEFAULT, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
     }
     
     @Override
diff --git 
a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMessageManager.java 
b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMessageManager.java
index 3af130f..2ee3e8a 100644
--- 
a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMessageManager.java
+++ 
b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMessageManager.java
@@ -28,6 +28,7 @@ import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.jpa.mail.model.JPAMailbox;
 import org.apache.james.mailbox.jpa.mail.model.openjpa.JPAMailboxMessage;
 import org.apache.james.mailbox.model.MessageAttachment;
@@ -62,7 +63,7 @@ public class JPAMessageManager extends StoreMessageManager {
                              StoreRightManager storeRightManager) {
 
         super(JPAMailboxManager.DEFAULT_NO_MESSAGE_CAPABILITIES, 
mapperFactory, index, eventBus, locker, mailbox,
-            quotaManager, quotaRootResolver, messageParser, messageIdFactory, 
batchSizes, storeRightManager);
+            quotaManager, quotaRootResolver, messageParser, messageIdFactory, 
batchSizes, storeRightManager, PreDeletionHook.NO_PRE_DELETION_HOOK);
     }
     
     @Override
diff --git 
a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
 
b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
index b9e5073..0b5524b 100644
--- 
a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
+++ 
b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
@@ -26,10 +26,17 @@ import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.jpa.openjpa.OpenJPAMailboxManager;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 
 public class JPAMailboxManagerTest extends 
MailboxManagerTest<OpenJPAMailboxManager> {
 
+    @Disabled("JPAMailboxManager is using DefaultMessageId which doesn't 
support full feature of a messageId, which is an essential" +
+        "element of the Vault")
+    @Nested
+    class HookTests {
+    }
+
     private static final JpaTestCluster JPA_TEST_CLUSTER = 
JpaTestCluster.create(JPAMailboxFixture.MAILBOX_PERSISTANCE_CLASSES);
     private Optional<OpenJPAMailboxManager> openJPAMailboxManager = 
Optional.empty();
     
diff --git 
a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java
 
b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java
index d82be9c..955257f 100644
--- 
a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java
+++ 
b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndexTest.java
@@ -78,7 +78,8 @@ public class LuceneMessageSearchIndexTest extends 
AbstractMessageSearchIndexTest
             annotationManager,
             storeRightManager,
             quotaComponents,
-            luceneMessageSearchIndex);
+            luceneMessageSearchIndex,
+            PreDeletionHook.NO_PRE_DELETION_HOOK);
 
         messageIdManager = new StoreMessageIdManager(
             storeMailboxManager,
diff --git 
a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
 
b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
index d5be3b6..8885135 100644
--- 
a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
+++ 
b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
@@ -22,10 +22,18 @@ import org.apache.james.junit.TemporaryFolderExtension;
 import org.apache.james.mailbox.MailboxManagerTest;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.store.StoreMailboxManager;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class DomainUserMaildirMailboxManagerTest extends 
MailboxManagerTest<StoreMailboxManager> {
 
+    @Disabled("Maildir is using DefaultMessageId which doesn't support full 
feature of a messageId, which is an essential" +
+        "element of the Vault")
+    @Nested
+    class HookTests {
+    }
+
     @RegisterExtension
     TemporaryFolderExtension temporaryFolder = new TemporaryFolderExtension();
     
@@ -42,4 +50,6 @@ public class DomainUserMaildirMailboxManagerTest extends 
MailboxManagerTest<Stor
     protected EventBus retrieveEventBus(StoreMailboxManager mailboxManager) {
         return mailboxManager.getEventBus();
     }
+
+
 }
diff --git 
a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
 
b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
index 08faae2..3e7280e 100644
--- 
a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
+++ 
b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
@@ -22,9 +22,18 @@ import org.apache.james.junit.TemporaryFolderExtension;
 import org.apache.james.mailbox.MailboxManagerTest;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.store.StoreMailboxManager;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class FullUserMaildirMailboxManagerTest extends 
MailboxManagerTest<StoreMailboxManager> {
+
+    @Disabled("Maildir is using DefaultMessageId which doesn't support full 
feature of a messageId, which is an essential" +
+        "element of the Vault")
+    @Nested
+    class HookTests {
+    }
+
     @RegisterExtension
     TemporaryFolderExtension temporaryFolder = new TemporaryFolderExtension();
     
diff --git 
a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java
 
b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java
index 5eb0490..4604f53 100644
--- 
a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java
+++ 
b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java
@@ -29,6 +29,7 @@ import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
 import org.apache.james.mailbox.events.InVMEventBus;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.store.Authenticator;
 import org.apache.james.mailbox.store.Authorizator;
 import org.apache.james.mailbox.store.JVMMailboxPathLocker;
@@ -72,7 +73,7 @@ public class MaildirMailboxManagerProvider {
 
         StoreMailboxManager manager = new StoreMailboxManager(mf, 
sessionProvider, new JVMMailboxPathLocker(),
             messageParser, new DefaultMessageId.Factory(), annotationManager, 
eventBus, storeRightManager,
-            quotaComponents, index, MailboxManagerConfiguration.DEFAULT);
+            quotaComponents, index, MailboxManagerConfiguration.DEFAULT, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
 
         return manager;
     }
diff --git 
a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java
 
b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java
index f6f6387..bd25f42 100644
--- 
a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java
+++ 
b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java
@@ -20,12 +20,14 @@
 package org.apache.james.mailbox.inmemory;
 
 import java.util.EnumSet;
+import java.util.Set;
 
 import javax.inject.Inject;
 
 import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.events.EventBus;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.store.MailboxManagerConfiguration;
 import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
@@ -56,9 +58,11 @@ public class InMemoryMailboxManager extends 
StoreMailboxManager {
                                   StoreMailboxAnnotationManager 
annotationManager,
                                   StoreRightManager storeRightManager,
                                   QuotaComponents quotaComponents,
-                                  MessageSearchIndex searchIndex) {
+                                  MessageSearchIndex searchIndex,
+                                  Set<PreDeletionHook> preDeletionHooks) {
         super(mailboxSessionMapperFactory, sessionProvider, locker, 
messageParser, messageIdFactory,
-            annotationManager, eventBus, storeRightManager, quotaComponents, 
searchIndex, MailboxManagerConfiguration.DEFAULT);
+            annotationManager, eventBus, storeRightManager, quotaComponents, 
searchIndex, MailboxManagerConfiguration.DEFAULT,
+            preDeletionHooks);
     }
 
     @Override
diff --git 
a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java
 
b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java
index c331b6a..645d0fb 100644
--- 
a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java
+++ 
b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java
@@ -8,6 +8,7 @@ import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.quota.QuotaManager;
@@ -40,7 +41,7 @@ public class InMemoryMessageManager extends 
StoreMessageManager {
                                   StoreRightManager storeRightManager) {
 
         super(InMemoryMailboxManager.MESSAGE_CAPABILITIES, mapperFactory, 
index, eventBus, locker, mailbox, quotaManager, quotaRootResolver,
-            messageParser, messageIdFactory, batchSizes, storeRightManager);
+            messageParser, messageIdFactory, batchSizes, storeRightManager, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
         this.mapperFactory = (InMemoryMailboxSessionMapperFactory) 
mapperFactory;
     }
 
diff --git 
a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
 
b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
index 7ad8bcf..889f35d 100644
--- 
a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
+++ 
b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
@@ -21,8 +21,16 @@ package org.apache.james.mailbox.inmemory;
 
 import org.apache.james.mailbox.MailboxManagerTest;
 import org.apache.james.mailbox.events.EventBus;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Nested;
 
 public class MemoryMailboxManagerTest extends 
MailboxManagerTest<InMemoryMailboxManager> {
+
+    @Disabled("will enable at later commits")
+    @Nested
+    class HookTests {
+    }
+
     @Override
     protected InMemoryMailboxManager provideMailboxManager() {
         return MemoryMailboxManagerProvider.provideMailboxManager();
diff --git 
a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMailboxManagerAttachmentTest.java
 
b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMailboxManagerAttachmentTest.java
index 2cc6bae..ebf76fa 100644
--- 
a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMailboxManagerAttachmentTest.java
+++ 
b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMailboxManagerAttachmentTest.java
@@ -30,6 +30,7 @@ import org.apache.james.mailbox.acl.GroupMembershipResolver;
 import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
 import org.apache.james.mailbox.events.InVMEventBus;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
 import org.apache.james.mailbox.inmemory.InMemoryMailboxSessionMapperFactory;
 import org.apache.james.mailbox.inmemory.InMemoryMessageId;
@@ -76,12 +77,12 @@ public class InMemoryMailboxManagerAttachmentTest extends 
AbstractMailboxManager
 
         StoreMailboxAnnotationManager annotationManager = new 
StoreMailboxAnnotationManager(mailboxSessionMapperFactory, storeRightManager);
         mailboxManager = new 
InMemoryMailboxManager(mailboxSessionMapperFactory, sessionProvider, new 
NoMailboxPathLocker(),
-                new MessageParser(), messageIdFactory, eventBus, 
annotationManager, storeRightManager, quotaComponents, index);
+                new MessageParser(), messageIdFactory, eventBus, 
annotationManager, storeRightManager, quotaComponents, index, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
         MessageParser failingMessageParser = mock(MessageParser.class);
         when(failingMessageParser.retrieveAttachments(any(InputStream.class)))
             .thenThrow(new RuntimeException("Message parser set to fail"));
         parseFailingMailboxManager = new 
InMemoryMailboxManager(mailboxSessionMapperFactory, sessionProvider, new 
NoMailboxPathLocker(),
-            failingMessageParser, messageIdFactory, eventBus, 
annotationManager, storeRightManager, quotaComponents, index);
+            failingMessageParser, messageIdFactory, eventBus, 
annotationManager, storeRightManager, quotaComponents, index, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
         super.setUp();
     }
 
diff --git 
a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
 
b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
index 9e5e5a5..8ae5009 100644
--- 
a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
+++ 
b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
@@ -173,7 +173,8 @@ public class InMemoryIntegrationResources implements 
IntegrationResources<StoreM
             annotationManager,
             storeRightManager,
             quotaComponents,
-            index);
+            index,
+            PreDeletionHook.NO_PRE_DELETION_HOOK);
 
         eventBus.register(listeningCurrentQuotaUpdater);
         eventBus.register(new 
MailboxAnnotationListener(mailboxSessionMapperFactory, sessionProvider));
diff --git 
a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryMessageIdManagerSideEffectTest.java
 
b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryMessageIdManagerSideEffectTest.java
index c99bb6b..0f84e06 100644
--- 
a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryMessageIdManagerSideEffectTest.java
+++ 
b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryMessageIdManagerSideEffectTest.java
@@ -83,7 +83,8 @@ public class InMemoryMessageIdManagerSideEffectTest extends 
AbstractMessageIdMan
             new StoreMailboxAnnotationManager(mapperFactory, rightManager),
             rightManager,
             quotaComponents,
-            index);
+            index,
+            preDeletionHooks);
         StoreMessageIdManager messageIdManager = new StoreMessageIdManager(
             mailboxManager,
             mapperFactory,
diff --git 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
index 7e46527..22af4a8 100644
--- 
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
+++ 
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
@@ -44,6 +44,7 @@ import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxExistsException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.exception.TooLongMailboxNameException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxACL.Rfc4314Rights;
 import org.apache.james.mailbox.model.MailboxACL.Right;
@@ -110,6 +111,7 @@ public class StoreMailboxManager implements MailboxManager {
     private final QuotaRootResolver quotaRootResolver;
     private final QuotaComponents quotaComponents;
     private final MessageSearchIndex index;
+    private final Set<PreDeletionHook> preDeletionHooks;
     protected final MailboxManagerConfiguration configuration;
 
     @Inject
@@ -117,7 +119,8 @@ public class StoreMailboxManager implements MailboxManager {
                                MailboxPathLocker locker, MessageParser 
messageParser,
                                MessageId.Factory messageIdFactory, 
MailboxAnnotationManager annotationManager,
                                EventBus eventBus, StoreRightManager 
storeRightManager,
-                               QuotaComponents quotaComponents, 
MessageSearchIndex searchIndex, MailboxManagerConfiguration configuration) {
+                               QuotaComponents quotaComponents, 
MessageSearchIndex searchIndex, MailboxManagerConfiguration configuration,
+                               Set<PreDeletionHook> preDeletionHooks) {
         Preconditions.checkNotNull(eventBus);
         Preconditions.checkNotNull(mailboxSessionMapperFactory);
 
@@ -134,6 +137,7 @@ public class StoreMailboxManager implements MailboxManager {
         this.quotaComponents = quotaComponents;
         this.index = searchIndex;
         this.configuration = configuration;
+        this.preDeletionHooks = preDeletionHooks;
     }
 
     public QuotaComponents getQuotaComponents() {
@@ -202,6 +206,10 @@ public class StoreMailboxManager implements MailboxManager 
{
         return messageParser;
     }
 
+    public Set<PreDeletionHook> getPreDeletionHooks() {
+        return preDeletionHooks;
+    }
+
     /**
      * Generate an return the next uid validity
      *
@@ -251,7 +259,7 @@ public class StoreMailboxManager implements MailboxManager {
         return new StoreMessageManager(DEFAULT_NO_MESSAGE_CAPABILITIES, 
getMapperFactory(), getMessageSearchIndex(), getEventBus(),
                 getLocker(), mailbox, quotaManager,
             getQuotaComponents().getQuotaRootResolver(), getMessageParser(), 
getMessageIdFactory(), configuration.getBatchSizes(),
-            getStoreRightManager());
+            getStoreRightManager(), preDeletionHooks);
     }
 
     /**
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 7b9c641..1de663a 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
@@ -19,6 +19,8 @@
 
 package org.apache.james.mailbox.store;
 
+import static 
org.apache.james.mailbox.extension.PreDeletionHook.DeleteOperation;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -29,6 +31,7 @@ import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
@@ -44,6 +47,7 @@ import org.apache.james.mailbox.MailboxPathLocker;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.MetadataWithMailboxId;
 import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
@@ -51,6 +55,7 @@ import org.apache.james.mailbox.events.MailboxListener;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.ReadOnlyException;
 import org.apache.james.mailbox.exception.UnsupportedRightException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxCounters;
@@ -89,15 +94,19 @@ import org.apache.james.mime4j.stream.MimeTokenStream;
 import org.apache.james.mime4j.stream.RecursionMode;
 import org.apache.james.util.BodyOffsetInputStream;
 import org.apache.james.util.IteratorWrapper;
+import org.apache.james.util.StreamUtils;
 import org.apache.james.util.streams.Iterators;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.github.fge.lambdas.Throwing;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSortedMap;
 
 import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
 
 /**
  * Base class for {@link MessageManager}
@@ -112,6 +121,7 @@ import reactor.core.publisher.Flux;
  */
 public class StoreMessageManager implements MessageManager {
 
+    private static final int NO_LIMIT = -1;
     private static final MailboxCounters ZERO_MAILBOX_COUNTERS = 
MailboxCounters.builder()
         .count(0)
         .unseen(0)
@@ -148,12 +158,13 @@ public class StoreMessageManager implements 
MessageManager {
     private final MessageParser messageParser;
     private final Factory messageIdFactory;
     private final BatchSizes batchSizes;
+    private final Set<PreDeletionHook> preDeletionHooks;
 
     public StoreMessageManager(EnumSet<MailboxManager.MessageCapabilities> 
messageCapabilities, MailboxSessionMapperFactory mapperFactory,
                                MessageSearchIndex index, EventBus eventBus,
                                MailboxPathLocker locker, Mailbox mailbox,
                                QuotaManager quotaManager, QuotaRootResolver 
quotaRootResolver, MessageParser messageParser, MessageId.Factory 
messageIdFactory, BatchSizes batchSizes,
-                               StoreRightManager storeRightManager) {
+                               StoreRightManager storeRightManager, 
Set<PreDeletionHook> preDeletionHooks) {
         this.messageCapabilities = messageCapabilities;
         this.eventBus = eventBus;
         this.mailbox = mailbox;
@@ -166,6 +177,7 @@ public class StoreMessageManager implements MessageManager {
         this.messageIdFactory = messageIdFactory;
         this.batchSizes = batchSizes;
         this.storeRightManager = storeRightManager;
+        this.preDeletionHooks = preDeletionHooks;
     }
 
     protected Factory getMessageIdFactory() {
@@ -284,6 +296,8 @@ public class StoreMessageManager implements MessageManager {
     private Map<MessageUid, MessageMetaData> deleteMessages(List<MessageUid> 
messageUids, MailboxSession session) throws MailboxException {
         MessageMapper messageMapper = mapperFactory.getMessageMapper(session);
 
+        runPredeletionHooks(messageUids, session);
+
         return messageMapper.execute(
             () -> messageMapper.deleteMessages(getMailboxEntity(), 
messageUids));
     }
@@ -715,6 +729,24 @@ public class StoreMessageManager implements MessageManager 
{
 
     }
 
+    private void runPredeletionHooks(List<MessageUid> uids, MailboxSession 
session) throws MailboxException {
+        MessageMapper messageMapper = mapperFactory.getMessageMapper(session);
+
+        DeleteOperation deleteOperation = 
Flux.fromIterable(MessageRange.toRanges(uids))
+            .publishOn(Schedulers.elastic())
+            .flatMap(range -> Mono.fromCallable(() -> 
messageMapper.findInMailbox(mailbox, range, FetchType.Metadata, NO_LIMIT))
+                .flatMapMany(iterator -> 
Flux.fromStream(Iterators.toStream(iterator))))
+            .map(mailboxMessage -> 
MetadataWithMailboxId.from(mailboxMessage.metaData(), 
mailboxMessage.getMailboxId()))
+            .collect(Guavate.toImmutableList())
+            .map(DeleteOperation::from)
+            .block();
+
+        Flux.fromIterable(preDeletionHooks)
+            .publishOn(Schedulers.elastic())
+            .flatMap(hook -> hook.notifyDelete(deleteOperation))
+            .blockLast();
+    }
+
     @Override
     public Iterator<MessageUid> search(SearchQuery query, MailboxSession 
mailboxSession) throws MailboxException {
         if (query.equals(new SearchQuery(SearchQuery.all()))) {
diff --git 
a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java
 
b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java
index b5b5ca1..b32ffa9 100644
--- 
a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java
+++ 
b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java
@@ -36,6 +36,7 @@ import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.exception.NotAdminException;
 import org.apache.james.mailbox.exception.UserDoesNotExistException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
@@ -93,7 +94,7 @@ public class StoreMailboxManagerTest {
 
         storeMailboxManager = new StoreMailboxManager(mockedMapperFactory, 
sessionProvider,
                 new JVMMailboxPathLocker(), new MessageParser(), 
messageIdFactory,
-                annotationManager, eventBus, storeRightManager, 
quotaComponents, index, MailboxManagerConfiguration.DEFAULT);
+                annotationManager, eventBus, storeRightManager, 
quotaComponents, index, MailboxManagerConfiguration.DEFAULT, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
     }
 
     @Test(expected = MailboxNotFoundException.class)
diff --git 
a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/CassandraReIndexerImplTest.java
 
b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/CassandraReIndexerImplTest.java
index 7161b38..ca278ee 100644
--- 
a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/CassandraReIndexerImplTest.java
+++ 
b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/CassandraReIndexerImplTest.java
@@ -35,6 +35,7 @@ import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.cassandra.CassandraMailboxManager;
 import org.apache.james.mailbox.cassandra.CassandraMailboxManagerProvider;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.indexer.ReIndexer;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
@@ -61,7 +62,8 @@ public class CassandraReIndexerImplTest {
 
     @BeforeEach
     void setUp(CassandraCluster cassandra) {
-        mailboxManager = 
CassandraMailboxManagerProvider.provideMailboxManager(cassandra.getConf(), 
cassandra.getTypesProvider());
+        mailboxManager = 
CassandraMailboxManagerProvider.provideMailboxManager(cassandra.getConf(), 
cassandra.getTypesProvider(),
+            PreDeletionHook.NO_PRE_DELETION_HOOK);
         MailboxSessionMapperFactory mailboxSessionMapperFactory = 
mailboxManager.getMapperFactory();
         messageSearchIndex = mock(ListeningMessageSearchIndex.class);
         reIndexer = new ReIndexerImpl(new ReIndexerPerformer(mailboxManager, 
messageSearchIndex, mailboxSessionMapperFactory),
diff --git 
a/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
 
b/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
index 2b4d901..62a64a8 100644
--- 
a/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
+++ 
b/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
@@ -40,6 +40,7 @@ import 
org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaDao;
 import 
org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaManager;
 import org.apache.james.mailbox.events.InVMEventBus;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.quota.QuotaRootResolver;
 import org.apache.james.mailbox.store.JVMMailboxPathLocker;
 import org.apache.james.mailbox.store.MailboxManagerConfiguration;
@@ -112,7 +113,7 @@ public class CassandraHostSystem extends 
JamesImapHostSystem {
 
         mailboxManager = new CassandraMailboxManager(mapperFactory, 
sessionProvider,
             new JVMMailboxPathLocker(), new MessageParser(), messageIdFactory,
-            eventBus, annotationManager, storeRightManager, quotaComponents, 
index, MailboxManagerConfiguration.DEFAULT);
+            eventBus, annotationManager, storeRightManager, quotaComponents, 
index, MailboxManagerConfiguration.DEFAULT, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
 
         eventBus.register(quotaUpdater);
 
diff --git 
a/mpt/impl/imap-mailbox/elasticsearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/ElasticSearchHostSystem.java
 
b/mpt/impl/imap-mailbox/elasticsearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/ElasticSearchHostSystem.java
index d599899..e0c85b5 100644
--- 
a/mpt/impl/imap-mailbox/elasticsearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/ElasticSearchHostSystem.java
+++ 
b/mpt/impl/imap-mailbox/elasticsearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/ElasticSearchHostSystem.java
@@ -51,6 +51,7 @@ import 
org.apache.james.mailbox.elasticsearch.search.ElasticSearchSearcher;
 import org.apache.james.mailbox.events.InVMEventBus;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
 import org.apache.james.mailbox.inmemory.InMemoryMailboxSessionMapperFactory;
@@ -140,7 +141,8 @@ public class ElasticSearchHostSystem extends 
JamesImapHostSystem {
             annotationManager,
             storeRightManager,
             quotaComponents,
-            searchIndex);
+            searchIndex,
+            PreDeletionHook.NO_PRE_DELETION_HOOK);
 
         eventBus.register(searchIndex);
 
diff --git 
a/mpt/impl/imap-mailbox/lucenesearch/src/test/java/org/apache/james/mpt/imapmailbox/lucenesearch/host/LuceneSearchHostSystem.java
 
b/mpt/impl/imap-mailbox/lucenesearch/src/test/java/org/apache/james/mpt/imapmailbox/lucenesearch/host/LuceneSearchHostSystem.java
index 52756d6..a2a7c3d 100644
--- 
a/mpt/impl/imap-mailbox/lucenesearch/src/test/java/org/apache/james/mpt/imapmailbox/lucenesearch/host/LuceneSearchHostSystem.java
+++ 
b/mpt/impl/imap-mailbox/lucenesearch/src/test/java/org/apache/james/mpt/imapmailbox/lucenesearch/host/LuceneSearchHostSystem.java
@@ -37,6 +37,7 @@ import 
org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
 import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
 import org.apache.james.mailbox.events.InVMEventBus;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
 import org.apache.james.mailbox.inmemory.InMemoryMailboxSessionMapperFactory;
@@ -118,7 +119,8 @@ public class LuceneSearchHostSystem extends 
JamesImapHostSystem {
                 new StoreMailboxAnnotationManager(mapperFactory, rightManager),
                 rightManager,
                 QuotaComponents.disabled(sessionProvider, mapperFactory),
-                searchIndex);
+                searchIndex,
+                PreDeletionHook.NO_PRE_DELETION_HOOK);
 
             searchIndex.setEnableSuffixMatch(true);
 
diff --git 
a/mpt/impl/imap-mailbox/maildir/src/test/java/org/apache/james/mpt/imapmailbox/maildir/host/MaildirHostSystem.java
 
b/mpt/impl/imap-mailbox/maildir/src/test/java/org/apache/james/mpt/imapmailbox/maildir/host/MaildirHostSystem.java
index ae23921..4612fea 100644
--- 
a/mpt/impl/imap-mailbox/maildir/src/test/java/org/apache/james/mpt/imapmailbox/maildir/host/MaildirHostSystem.java
+++ 
b/mpt/impl/imap-mailbox/maildir/src/test/java/org/apache/james/mpt/imapmailbox/maildir/host/MaildirHostSystem.java
@@ -35,6 +35,7 @@ import 
org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
 import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
 import org.apache.james.mailbox.events.InVMEventBus;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
+import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.maildir.MaildirMailboxSessionMapperFactory;
 import org.apache.james.mailbox.maildir.MaildirStore;
 import org.apache.james.mailbox.store.JVMMailboxPathLocker;
@@ -85,7 +86,7 @@ public class MaildirHostSystem extends JamesImapHostSystem {
 
         mailboxManager = new StoreMailboxManager(mailboxSessionMapperFactory, 
sessionProvider, locker,
             messageParser, new DefaultMessageId.Factory(), annotationManager, 
eventBus, storeRightManager, quotaComponents,
-            index, MailboxManagerConfiguration.DEFAULT);
+            index, MailboxManagerConfiguration.DEFAULT, 
PreDeletionHook.NO_PRE_DELETION_HOOK);
 
         ImapProcessor defaultImapProcessorFactory =
                 DefaultImapProcessorFactory.createDefaultProcessor(


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

Reply via email to