You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2020/12/07 03:57:30 UTC

[james-project] branch master updated (97c577c -> bce3fb8)

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

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


    from 97c577c  JAMES-3460 Method to check updated flags
     new b44a5ed  JAMES-2543 updgrades MPT impl smtp to junit 5
     new 9f1bf0c  JAMES-2543 upgrades SMTP protocol tests to junit 5
     new 4823197  JAMES-3435 CRDT friendly version of CassandraACLDAO
     new 461d1c6  JAMES-3435 Migration task for CassandraACLDAOV2 adoption
     new 46e0a29  JAMES-3435 User rights DAO was not cleared upon ACL deletes
     new 9449c83  JAMES-2393 Dispatching an EventSourcing command can return the generated events
     new 86a044f  JAMES-3435 Pilot Cassandra mailbox ACL changes with an event sourcing system
     new 38024f9  JAMES-3435 CassandraACLDAOV2 no longer need to return ACLDiffs upon updates
     new fa3db02  JAMES-3435 Merge ACLReseted and ACLUpdated events
     new 9dc0a4c  JAMES-3435 Serialization tests for eventsourcing ACL POJOs
     new f7b1bcc  JAMES-3435 Pilot Cassandra mailbox ACL changes with an event sourcing system
     new 51cd0a5  JAMES-3435 CHANGELOG.md & upgrade-instructions.md
     new bce3fb8  JAMES 3400 Add Jwt Option

The 13 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 CHANGELOG.md                                       |   1 +
 .../versions/CassandraSchemaVersionManager.java    |   2 +-
 .../james/eventsourcing/CommandDispatcher.scala    |  10 +-
 .../james/eventsourcing/EventSourcingSystem.scala  |   4 +-
 .../java/org/apache/james/mailbox/acl/ACLDiff.java |  16 ++
 .../org/apache/james/mailbox/model/MailboxACL.java |   8 +-
 mailbox/cassandra/pom.xml                          |  12 ++
 .../james/mailbox/cassandra/ids/CassandraId.java   |   6 +-
 ...CassandraACLDAO.java => CassandraACLDAOV1.java} |  18 +--
 .../mailbox/cassandra/mail/CassandraACLDAOV2.java  | 155 ++++++++++++++++++
 .../mailbox/cassandra/mail/CassandraACLMapper.java | 155 ++++++++++++++++--
 .../cassandra/mail/eventsourcing/acl/ACLDTO.java   |  73 +++++++++
 .../eventsourcing/acl/ACLDiffDTO.java}             |  70 ++++----
 .../mail/eventsourcing/acl/ACLModule.java          |  74 +++++----
 .../eventsourcing/acl/ACLUpdated.java}             |  69 ++++----
 .../mail/eventsourcing/acl/ACLUpdatedDTO.java      | 106 ++++++++++++
 .../mail/eventsourcing/acl/AclV2DAOSubscriber.java |  32 ++--
 .../eventsourcing/acl/DeleteMailboxCommand.java    |  61 +++++++
 .../eventsourcing/acl/MailboxACLAggregate.java     |  91 +++++++++++
 .../mail/eventsourcing/acl/MailboxAggregateId.java |  37 +++--
 .../mail/eventsourcing/acl/SetACLCommand.java      |  68 ++++++++
 .../mail/eventsourcing/acl/UpdateACLCommand.java   |  70 ++++++++
 .../eventsourcing/acl/UserRightsDAOSubscriber.java |  28 ++--
 .../cassandra/mail/migration/AclV2Migration.java   | 114 +++++++++++++
 ...AclV2MigrationTaskAdditionalInformationDTO.java |  69 ++++++++
 .../mail/migration/AclV2MigrationTaskDTO.java      |  59 +++++++
 .../cassandra/modules/CassandraAclModule.java      |  13 ++
 .../cassandra/table/CassandraACLV2Table.java       |  20 +--
 .../cassandra/CassandraMailboxManagerTest.java     |  26 ++-
 .../cassandra/mail/CassandraACLMapperContract.java | 136 ++++++++++++++++
 ...pperTest.java => CassandraACLMapperV1Test.java} | 157 +++++-------------
 .../cassandra/mail/CassandraACLMapperV2Test.java   | 149 +++++++++++++++++
 .../mail/CassandraMailboxMapperAclTest.java        |   2 +
 .../mail/CassandraMailboxMapperGenericTest.java    |  23 ++-
 .../cassandra/mail/CassandraMailboxMapperTest.java |  37 +++--
 .../cassandra/mail/MailboxAggregateModule.java     |  32 ++--
 .../mail/eventsourcing/acl/ACLUpdatedDTOTest.java  |  72 +++++++++
 .../AclV2MigrationTaskSerializationTest.java       |  52 ++++++
 .../mail/migration/AclV2MigrationTest.java         | 128 +++++++++++++++
 .../mail/migration/MailboxPathV2MigrationTest.java |  30 +++-
 .../mailbox/cassandra/mail/utils/GuiceUtils.java   |  21 +++
 .../listeners/QuotaThresholdCrossingListener.java  |   3 +-
 .../mpt/smtp/AwsS3RabbitMQForwardSmtpTest.java     |  32 ++--
 .../smtp/AwsS3RabbitMQSmtpStarttlsCommandTest.java |  29 ++--
 .../CassandraRabbitMQAwsS3SmtpTestRuleFactory.java |  21 ++-
 .../james/mpt/smtp/CassandraForwardSmtpTest.java   |  26 ++-
 .../mpt/smtp/CassandraSmtpStarttlsCommandTest.java |  18 +--
 .../mpt/smtp/CassandraSmtpTestRuleFactory.java     |  15 +-
 .../org/apache/james/mpt/smtp/ForwardSmtpTest.java |  50 +++---
 .../apache/james/mpt/smtp/SmtpAuthCommandTest.java |   5 -
 .../james/mpt/smtp/SmtpStarttlsCommandTest.java    |  29 ++--
 .../apache/james/mpt/smtp/SmtpTestExtension.java   | 159 ++++++++++++++++++
 .../org/apache/james/mpt/smtp/SmtpTestRule.java    | 137 ----------------
 .../protocols/lmtp/AbstractLMTPServerTest.java     |  16 +-
 .../protocols/lmtp/netty/NettyLMTPSServerTest.java |   8 +-
 .../protocols/lmtp/netty/NettyLMTPServerTest.java  |   8 +-
 .../protocols/smtp/AbstractSMTPServerTest.java     |  48 +++---
 .../protocols/smtp/SMTPStartTlsResponseTest.java   |   5 +-
 .../smtp/core/fastfail/DNSRBLHandlerTest.java      |  20 +--
 .../smtp/core/fastfail/MaxRcptHandlerTest.java     |   6 +-
 .../core/fastfail/MaxUnknownCmdHandlerTest.java    |   4 +-
 .../fastfail/ResolvableEhloHeloHandlerTest.java    |  10 +-
 .../smtp/core/fastfail/SpamTrapHandlerTest.java    |   4 +-
 .../fastfail/ValidSenderDomainHandlerTest.java     |   6 +-
 .../james/protocols/smtp/hook/HookResultTest.java  |   4 +-
 .../protocols/smtp/netty/NettySMTPSServerTest.java |  12 +-
 .../protocols/smtp/netty/NettySMTPServerTest.java  |  12 +-
 .../smtp/netty/NettyStartTlsSMTPServerTest.java    |  32 ++--
 .../modules/mailbox/CassandraMailboxModule.java    |  16 +-
 .../modules/webadmin/CassandraRoutesModule.java    |   3 +
 .../impl/EventSourcingFilteringManagement.java     |   2 +-
 .../java/org/apache/james/cli/WebAdminCli.java     |  24 +++
 .../org/apache/james/cli/domain/DomainCommand.java |   5 +
 .../james/cli/domain/DomainCreateCommand.java      |   4 +-
 .../james/cli/domain/DomainDeleteCommand.java      |   4 +-
 .../james/cli/domain/DomainExistCommand.java       |   4 +-
 .../apache/james/cli/domain/DomainListCommand.java |   6 +-
 .../org/apache/james/cli/user/UserCommand.java     |   5 +
 .../apache/james/cli/user/UserCreateCommand.java   |   6 +-
 .../apache/james/cli/user/UserDeleteCommand.java   |   4 +-
 .../apache/james/cli/user/UserExistCommand.java    |   4 +-
 .../org/apache/james/cli/user/UserListCommand.java |   6 +-
 .../james/httpclient/FeignClientFactory.java       |  79 +++++++++
 .../java/org/apache/james/httpclient/JwtToken.java |  69 ++++----
 .../java/org/apache/james/cli/JwtOptionTest.java   | 178 +++++++++++++++++++++
 .../src/test/resources/valid_token_admin_false.jwt |   5 +
 .../src/test/resources/valid_token_admin_true.jwt  |   5 +
 .../task/eventsourcing/WorkerStatusListener.scala  |  15 +-
 server/testing/pom.xml                             |   4 +
 .../org/apache/james/utils/FakeSmtpExtension.java  | 168 +++++++++++++++++++
 upgrade-instructions.md                            |  17 ++
 91 files changed, 2880 insertions(+), 778 deletions(-)
 rename mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/{CassandraACLDAO.java => CassandraACLDAOV1.java} (94%)
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLDTO.java
 copy mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/{ids/CassandraId.java => mail/eventsourcing/acl/ACLDiffDTO.java} (53%)
 copy protocols/smtp/src/test/java/org/apache/james/protocols/smtp/SMTPStartTlsResponseTest.java => mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLModule.java (66%)
 copy mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/{ids/CassandraId.java => mail/eventsourcing/acl/ACLUpdated.java} (56%)
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTO.java
 copy mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraForwardSmtpTest.java => mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/AclV2DAOSubscriber.java (59%)
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/DeleteMailboxCommand.java
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxACLAggregate.java
 copy mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraSmtpStarttlsCommandTest.java => mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxAggregateId.java (56%)
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/SetACLCommand.java
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UpdateACLCommand.java
 copy mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraForwardSmtpTest.java => mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UserRightsDAOSubscriber.java (61%)
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2Migration.java
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskAdditionalInformationDTO.java
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskDTO.java
 copy protocols/smtp/src/test/java/org/apache/james/protocols/smtp/hook/HookResultTest.java => mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraACLV2Table.java (80%)
 create mode 100644 mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperContract.java
 rename mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/{CassandraACLMapperTest.java => CassandraACLMapperV1Test.java} (51%)
 create mode 100644 mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
 create mode 100644 mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTOTest.java
 create mode 100644 mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskSerializationTest.java
 create mode 100644 mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java
 create mode 100644 mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpTestExtension.java
 delete mode 100644 mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpTestRule.java
 create mode 100644 server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/FeignClientFactory.java
 copy protocols/smtp/src/test/java/org/apache/james/protocols/smtp/hook/HookResultTest.java => server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/JwtToken.java (65%)
 create mode 100644 server/protocols/webadmin-cli/src/test/java/org/apache/james/cli/JwtOptionTest.java
 create mode 100644 server/protocols/webadmin-cli/src/test/resources/valid_token_admin_false.jwt
 create mode 100644 server/protocols/webadmin-cli/src/test/resources/valid_token_admin_true.jwt
 create mode 100644 server/testing/src/main/java/org/apache/james/utils/FakeSmtpExtension.java


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


[james-project] 02/13: JAMES-2543 upgrades SMTP protocol tests to junit 5

Posted by bt...@apache.org.
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 9f1bf0c234d1a2449ab57eb37f5088561e38fb07
Author: Jean Helou <jh...@codamens.fr>
AuthorDate: Thu Dec 3 23:21:30 2020 +0100

    JAMES-2543 upgrades SMTP protocol tests to junit 5
---
 .../protocols/lmtp/AbstractLMTPServerTest.java     | 16 ++++----
 .../protocols/lmtp/netty/NettyLMTPSServerTest.java |  8 ++--
 .../protocols/lmtp/netty/NettyLMTPServerTest.java  |  8 ++--
 .../protocols/smtp/AbstractSMTPServerTest.java     | 48 +++++++++++-----------
 .../protocols/smtp/SMTPStartTlsResponseTest.java   |  5 ++-
 .../smtp/core/fastfail/DNSRBLHandlerTest.java      | 20 ++++-----
 .../smtp/core/fastfail/MaxRcptHandlerTest.java     |  6 +--
 .../core/fastfail/MaxUnknownCmdHandlerTest.java    |  4 +-
 .../fastfail/ResolvableEhloHeloHandlerTest.java    | 10 ++---
 .../smtp/core/fastfail/SpamTrapHandlerTest.java    |  4 +-
 .../fastfail/ValidSenderDomainHandlerTest.java     |  6 +--
 .../james/protocols/smtp/hook/HookResultTest.java  |  4 +-
 .../protocols/smtp/netty/NettySMTPSServerTest.java | 12 +++---
 .../protocols/smtp/netty/NettySMTPServerTest.java  | 12 +++---
 .../smtp/netty/NettyStartTlsSMTPServerTest.java    | 32 +++++++--------
 15 files changed, 98 insertions(+), 97 deletions(-)

diff --git a/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/AbstractLMTPServerTest.java b/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/AbstractLMTPServerTest.java
index f717fda..50820a1 100644
--- a/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/AbstractLMTPServerTest.java
+++ b/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/AbstractLMTPServerTest.java
@@ -45,7 +45,7 @@ import org.apache.james.protocols.smtp.hook.HookResult;
 import org.apache.james.protocols.smtp.hook.MessageHook;
 import org.apache.james.protocols.smtp.utils.TestMessageHook;
 import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 public abstract class AbstractLMTPServerTest extends AbstractSMTPServerTest {
 
@@ -68,18 +68,18 @@ public abstract class AbstractLMTPServerTest extends AbstractSMTPServerTest {
 
     @Ignore("LMTP can't handle the queue")
     @Override
-    public void testDeliveryWith4SimultaneousThreads() {
+    protected void testDeliveryWith4SimultaneousThreads() {
     }
 
     @Ignore("Disable")
     @Override
-    public void testInvalidNoBracketsEnformance() throws Exception {
+    protected void testInvalidNoBracketsEnformance() throws Exception {
     }
 
 
     @Ignore("Disable")
     @Override
-    public void testHeloEnforcement() throws Exception {
+    protected void testHeloEnforcement() throws Exception {
     }
 
 
@@ -90,7 +90,7 @@ public abstract class AbstractLMTPServerTest extends AbstractSMTPServerTest {
 
 
     @Override
-    public void testMailWithoutBrackets() throws Exception {
+    protected void testMailWithoutBrackets() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         ProtocolServer server = null;
         try {
@@ -125,7 +125,7 @@ public abstract class AbstractLMTPServerTest extends AbstractSMTPServerTest {
 
 
     @Override
-    public void testRcptWithoutBrackets() throws Exception {
+    protected void testRcptWithoutBrackets() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         ProtocolServer server = null;
         try {
@@ -161,7 +161,7 @@ public abstract class AbstractLMTPServerTest extends AbstractSMTPServerTest {
 
 
     @Test
-    public void testEhloNotSupported() throws Exception {
+    protected void testEhloNotSupported() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         ProtocolServer server = null;
         try {
@@ -191,7 +191,7 @@ public abstract class AbstractLMTPServerTest extends AbstractSMTPServerTest {
     }
 
     @Test
-    public void testDeliveryHook() throws Exception {
+    void testDeliveryHook() throws Exception {
         TestDeliverHook deliverHook = new TestDeliverHook();
         
         ProtocolServer server = null;
diff --git a/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/netty/NettyLMTPSServerTest.java b/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/netty/NettyLMTPSServerTest.java
index 5fbf322..95e58b3 100644
--- a/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/netty/NettyLMTPSServerTest.java
+++ b/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/netty/NettyLMTPSServerTest.java
@@ -9,8 +9,8 @@ import org.apache.james.protocols.api.utils.BogusSslContextFactory;
 import org.apache.james.protocols.lmtp.AbstractLMTPSServerTest;
 import org.apache.james.protocols.netty.NettyServer;
 import org.jboss.netty.util.HashedWheelTimer;
-import org.junit.After;
-import org.junit.Before;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 
 public class NettyLMTPSServerTest extends AbstractLMTPSServerTest {
 
@@ -19,12 +19,12 @@ public class NettyLMTPSServerTest extends AbstractLMTPSServerTest {
 
     private HashedWheelTimer hashedWheelTimer;
 
-    @Before
+    @BeforeEach
     public void setup() {
         hashedWheelTimer = new HashedWheelTimer();
     }
 
-    @After
+    @AfterEach
     public void teardown() {
         hashedWheelTimer.stop();
     }
diff --git a/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/netty/NettyLMTPServerTest.java b/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/netty/NettyLMTPServerTest.java
index 30e7716..8a75e71 100644
--- a/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/netty/NettyLMTPServerTest.java
+++ b/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/netty/NettyLMTPServerTest.java
@@ -25,8 +25,8 @@ import org.apache.james.protocols.api.ProtocolServer;
 import org.apache.james.protocols.lmtp.AbstractLMTPServerTest;
 import org.apache.james.protocols.netty.NettyServer;
 import org.jboss.netty.util.HashedWheelTimer;
-import org.junit.After;
-import org.junit.Before;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 
 public class NettyLMTPServerTest extends AbstractLMTPServerTest {
 
@@ -35,12 +35,12 @@ public class NettyLMTPServerTest extends AbstractLMTPServerTest {
 
     private HashedWheelTimer hashedWheelTimer;
 
-    @Before
+    @BeforeEach
     public void setup() {
         hashedWheelTimer = new HashedWheelTimer();
     }
 
-    @After
+    @AfterEach
     public void teardown() {
         hashedWheelTimer.stop();
     }
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/AbstractSMTPServerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/AbstractSMTPServerTest.java
index 97203ec..71d8979 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/AbstractSMTPServerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/AbstractSMTPServerTest.java
@@ -51,7 +51,7 @@ import org.apache.james.protocols.smtp.hook.MessageHook;
 import org.apache.james.protocols.smtp.hook.RcptHook;
 import org.apache.james.protocols.smtp.utils.TestMessageHook;
 import org.apache.james.util.concurrency.ConcurrentTestRunner;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 import com.google.common.io.CharStreams;
 
@@ -63,7 +63,7 @@ public abstract class AbstractSMTPServerTest {
     protected static final String RCPT2 = "rpct2@domain";
 
     @Test
-    public void testSimpleDelivery() throws Exception {
+    void testSimpleDelivery() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         ProtocolServer server = null;
         try {
@@ -90,7 +90,7 @@ public abstract class AbstractSMTPServerTest {
     }
     
     @Test
-    public void testDeliveryWith4SimultaneousThreads() throws Exception {
+    protected void testDeliveryWith4SimultaneousThreads() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         ProtocolServer server = null;
         try {
@@ -155,7 +155,7 @@ public abstract class AbstractSMTPServerTest {
     }
     
     @Test
-    public void testStartTlsNotSupported() throws Exception {
+    void testStartTlsNotSupported() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         
         ProtocolServer server = null;
@@ -187,7 +187,7 @@ public abstract class AbstractSMTPServerTest {
     }
     
     @Test
-    public void testUnknownCommand() throws Exception {
+    void testUnknownCommand() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         
         ProtocolServer server = null;
@@ -219,7 +219,7 @@ public abstract class AbstractSMTPServerTest {
     }
     
     @Test
-    public void testNoop() throws Exception {
+    void testNoop() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         
         ProtocolServer server = null;
@@ -252,7 +252,7 @@ public abstract class AbstractSMTPServerTest {
     
     
     @Test
-    public void testMailWithoutBrackets() throws Exception {
+    protected void testMailWithoutBrackets() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         
         ProtocolServer server = null;
@@ -294,7 +294,7 @@ public abstract class AbstractSMTPServerTest {
 
 
     @Test
-    public void testInvalidHelo() throws Exception {
+    void testInvalidHelo() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         
         ProtocolServer server = null;
@@ -327,7 +327,7 @@ public abstract class AbstractSMTPServerTest {
     
 
     @Test
-    public void testRcptWithoutBrackets() throws Exception {
+    protected void testRcptWithoutBrackets() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         
         ProtocolServer server = null;
@@ -368,7 +368,7 @@ public abstract class AbstractSMTPServerTest {
     
     
     @Test
-    public void testInvalidNoBracketsEnformance() throws Exception {
+    protected void testInvalidNoBracketsEnformance() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         
         ProtocolServer server = null;
@@ -411,7 +411,7 @@ public abstract class AbstractSMTPServerTest {
     
     
     @Test
-    public void testHeloEnforcement() throws Exception {
+    protected void testHeloEnforcement() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         
         ProtocolServer server = null;
@@ -445,7 +445,7 @@ public abstract class AbstractSMTPServerTest {
     }
     
     @Test
-    public void testHeloEnforcementDisabled() throws Exception {
+    protected void testHeloEnforcementDisabled() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         
         ProtocolServer server = null;
@@ -482,7 +482,7 @@ public abstract class AbstractSMTPServerTest {
     
     
     @Test
-    public void testHeloHookPermanentError() throws Exception {
+    void testHeloHookPermanentError() throws Exception {
         HeloHook hook = (session, helo) -> HookResult.DENY;
         
         ProtocolServer server = null;
@@ -514,7 +514,7 @@ public abstract class AbstractSMTPServerTest {
     
     
     @Test
-    public void testHeloHookTempraryError() throws Exception {
+    void testHeloHookTempraryError() throws Exception {
         HeloHook hook = (session, helo) -> HookResult.DENYSOFT;
         
         ProtocolServer server = null;
@@ -545,7 +545,7 @@ public abstract class AbstractSMTPServerTest {
     }
     
     @Test
-    public void testMailHookPermanentError() throws Exception {
+    void testMailHookPermanentError() throws Exception {
         MailHook hook = new MailHook() {
             @Override
             public HookResult doMail(SMTPSession session, MaybeSender sender) {
@@ -584,7 +584,7 @@ public abstract class AbstractSMTPServerTest {
     }
     
     @Test
-    public void testMailHookTemporaryError() throws Exception {
+    void testMailHookTemporaryError() throws Exception {
         MailHook hook = new MailHook() {
             @Override
             public HookResult doMail(SMTPSession session, MaybeSender sender) {
@@ -624,7 +624,7 @@ public abstract class AbstractSMTPServerTest {
     
     
     @Test
-    public void testRcptHookPermanentError() throws Exception {
+    void testRcptHookPermanentError() throws Exception {
         RcptHook hook = new RcptHook() {
             @Override
             public HookResult doRcpt(SMTPSession session, MaybeSender sender, MailAddress rcpt) {
@@ -677,7 +677,7 @@ public abstract class AbstractSMTPServerTest {
     
 
     @Test
-    public void testRcptHookTemporaryError() throws Exception {
+    void testRcptHookTemporaryError() throws Exception {
         RcptHook hook = new RcptHook() {
             @Override
             public HookResult doRcpt(SMTPSession session, MaybeSender sender, MailAddress rcpt) {
@@ -728,7 +728,7 @@ public abstract class AbstractSMTPServerTest {
     }
     
     @Test
-    public void testNullSender() throws Exception {
+    void testNullSender() throws Exception {
         ProtocolServer server = null;
         try {
             server = createServer(createProtocol());
@@ -763,7 +763,7 @@ public abstract class AbstractSMTPServerTest {
     }
     
     @Test
-    public void testMessageHookPermanentError() throws Exception {
+    void testMessageHookPermanentError() throws Exception {
         TestMessageHook testHook = new TestMessageHook();
 
         MessageHook hook = (session, mail) -> HookResult.DENY;
@@ -809,7 +809,7 @@ public abstract class AbstractSMTPServerTest {
     
     
     @Test
-    public void testMessageHookTemporaryError() throws Exception {
+    void testMessageHookTemporaryError() throws Exception {
         TestMessageHook testHook = new TestMessageHook();
 
         MessageHook hook = (session, mail) -> HookResult.DENYSOFT;
@@ -856,7 +856,7 @@ public abstract class AbstractSMTPServerTest {
   
     
     @Test
-    public void testConnectHandlerPermananet() throws Exception {
+    void testConnectHandlerPermananet() throws Exception {
         ConnectHandler<SMTPSession> connectHandler = session -> new SMTPResponse("554", "Bye Bye");
         
         ProtocolServer server = null;
@@ -883,7 +883,7 @@ public abstract class AbstractSMTPServerTest {
     
     
     @Test
-    public void testConnectHandlerTemporary() throws Exception {
+    void testConnectHandlerTemporary() throws Exception {
         ConnectHandler<SMTPSession> connectHandler = session -> new SMTPResponse("451", "Bye Bye");
         
         ProtocolServer server = null;
@@ -908,7 +908,7 @@ public abstract class AbstractSMTPServerTest {
     }
     
     @Test
-    public void testDisconnectHandler() throws Exception {
+    void testDisconnectHandler() throws Exception {
         
         final AtomicBoolean called = new AtomicBoolean(false);
         DisconnectHandler<SMTPSession> handler = session -> called.set(true);
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/SMTPStartTlsResponseTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/SMTPStartTlsResponseTest.java
index 112a338..7306dc5 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/SMTPStartTlsResponseTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/SMTPStartTlsResponseTest.java
@@ -22,7 +22,8 @@ package org.apache.james.protocols.smtp;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import org.apache.james.protocols.api.StartTlsResponse;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
+
 
 public class SMTPStartTlsResponseTest {
 
@@ -30,7 +31,7 @@ public class SMTPStartTlsResponseTest {
      * Test for PROTOCOLS-89
      */
     @Test
-    public void testImmutable() {
+    void testImmutable() {
         SMTPStartTlsResponse response = new SMTPStartTlsResponse("554", "Reject");
         assertThat(response).isInstanceOf(StartTlsResponse.class);
         assertThat(response.immutable()).isInstanceOf(StartTlsResponse.class);
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandlerTest.java
index 2265aad..a0b48b6 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandlerTest.java
@@ -38,8 +38,8 @@ import org.apache.james.core.MaybeSender;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 import com.google.common.base.Preconditions;
 
@@ -51,8 +51,8 @@ public class DNSRBLHandlerTest {
 
     private boolean relaying = false;   
 
-    @Before
-    public void setUp() throws Exception {
+    @BeforeEach
+    void setUp() throws Exception {
         setRelayingAllowed(false);
     }
 
@@ -184,7 +184,7 @@ public class DNSRBLHandlerTest {
 
     // ip is blacklisted and has txt details
     @Test
-    public void testBlackListedTextPresent() throws Exception {
+    void testBlackListedTextPresent() throws Exception {
         DNSRBLHandler rbl = createHandler();
        
         setupMockedSMTPSession(new MailAddress("any@domain"));
@@ -198,7 +198,7 @@ public class DNSRBLHandlerTest {
 
     // ip is blacklisted and has txt details but we don'T want to retrieve the txt record
     @Test
-    public void testGetNoDetail() throws Exception {
+    void testGetNoDetail() throws Exception {
         DNSRBLHandler rbl = createHandler();
         setupMockedSMTPSession(new MailAddress("any@domain"));
 
@@ -211,7 +211,7 @@ public class DNSRBLHandlerTest {
 
     // ip is allowed to relay
     @Test
-    public void testRelayAllowed() throws Exception {
+    void testRelayAllowed() throws Exception {
         DNSRBLHandler rbl = createHandler();
         setRelayingAllowed(true);
         setupMockedSMTPSession(new MailAddress("any@domain"));
@@ -225,7 +225,7 @@ public class DNSRBLHandlerTest {
 
     // ip not on blacklist
     @Test
-    public void testNotBlackListed() throws Exception {
+    void testNotBlackListed() throws Exception {
         DNSRBLHandler rbl = createHandler();
 
         setRemoteIp("192.168.0.1");
@@ -240,7 +240,7 @@ public class DNSRBLHandlerTest {
 
     // ip on blacklist without txt details
     @Test
-    public void testBlackListedNoTxt() throws Exception {
+    void testBlackListedNoTxt() throws Exception {
         DNSRBLHandler rbl = createHandler();
 
         setRemoteIp("127.0.0.3");
@@ -255,7 +255,7 @@ public class DNSRBLHandlerTest {
 
     // ip on whitelist
     @Test
-    public void testWhiteListed() throws Exception {
+    void testWhiteListed() throws Exception {
         DNSRBLHandler rbl = createHandler();
 
         setRemoteIp("127.0.0.2");
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxRcptHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxRcptHandlerTest.java
index 72ee259..b195a21 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxRcptHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxRcptHandlerTest.java
@@ -29,7 +29,7 @@ import org.apache.james.core.MaybeSender;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookReturnCode;
 import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 public class MaxRcptHandlerTest {
     
@@ -56,7 +56,7 @@ public class MaxRcptHandlerTest {
     }
     
     @Test
-    public void testRejectMaxRcpt() throws Exception {
+    void testRejectMaxRcpt() throws Exception {
         SMTPSession session = setupMockedSession(3);
         MaxRcptHandler handler = new MaxRcptHandler();
         
@@ -68,7 +68,7 @@ public class MaxRcptHandlerTest {
   
   
     @Test
-    public void testNotRejectMaxRcpt() throws Exception {
+    void testNotRejectMaxRcpt() throws Exception {
         SMTPSession session = setupMockedSession(3);
         MaxRcptHandler handler = new MaxRcptHandler();    
 
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandlerTest.java
index 98f9412..e6be609 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandlerTest.java
@@ -29,7 +29,7 @@ import java.util.Optional;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookReturnCode;
 import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 import com.google.common.base.Preconditions;
 
@@ -37,7 +37,7 @@ public class MaxUnknownCmdHandlerTest {
 
     
     @Test
-    public void testRejectAndClose() throws Exception {
+    void testRejectAndClose() throws Exception {
         SMTPSession session = new BaseFakeSMTPSession() {
             private final HashMap<AttachmentKey<?>, Object> map = new HashMap<>();
 
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandlerTest.java
index cf2052b..c53184a 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandlerTest.java
@@ -35,7 +35,7 @@ import org.apache.james.core.Username;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookReturnCode;
 import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 import com.google.common.base.Preconditions;
 
@@ -129,7 +129,7 @@ public class ResolvableEhloHeloHandlerTest {
     }
     
     @Test
-    public void testRejectInvalidHelo() throws Exception {
+    void testRejectInvalidHelo() throws Exception {
         MailAddress mailAddress = new MailAddress("test@localhost");
         SMTPSession session = setupMockSession(INVALID_HOST, false, false, null, mailAddress);
         ResolvableEhloHeloHandler handler = createHandler();
@@ -142,7 +142,7 @@ public class ResolvableEhloHeloHandlerTest {
     }
     
     @Test
-    public void testNotRejectValidHelo() throws Exception {
+    void testNotRejectValidHelo() throws Exception {
         MailAddress mailAddress = new MailAddress("test@localhost");
         SMTPSession session = setupMockSession(VALID_HOST, false, false, null, mailAddress);
         ResolvableEhloHeloHandler handler = createHandler();
@@ -156,7 +156,7 @@ public class ResolvableEhloHeloHandlerTest {
     }
    
     @Test
-    public void testRejectInvalidHeloAuthUser() throws Exception {
+    void testRejectInvalidHeloAuthUser() throws Exception {
         MailAddress mailAddress = new MailAddress("test@localhost");
         SMTPSession session = setupMockSession(INVALID_HOST, false, true, Username.of("valid@user"), mailAddress);
         ResolvableEhloHeloHandler handler = createHandler();
@@ -172,7 +172,7 @@ public class ResolvableEhloHeloHandlerTest {
     
    
     @Test
-    public void testRejectRelay() throws Exception {
+    void testRejectRelay() throws Exception {
         MailAddress mailAddress = new MailAddress("test@localhost");
         SMTPSession session = setupMockSession(INVALID_HOST, true, false, null, mailAddress);
         ResolvableEhloHeloHandler handler = createHandler();
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/SpamTrapHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/SpamTrapHandlerTest.java
index 3e7a528..41766a1 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/SpamTrapHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/SpamTrapHandlerTest.java
@@ -30,7 +30,7 @@ import org.apache.james.core.MaybeSender;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookReturnCode;
 import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 public class SpamTrapHandlerTest {
     private static final String SPAM_TRAP_RECIP1 = "spamtrap1@localhost";
@@ -51,7 +51,7 @@ public class SpamTrapHandlerTest {
     }
     
     @Test
-    public void testSpamTrap() throws Exception {
+    void testSpamTrap() throws Exception {
         String ip = "192.168.100.1";
         String ip2 = "192.168.100.2";
         long blockTime = 2000;
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ValidSenderDomainHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ValidSenderDomainHandlerTest.java
index 685b4f2..903f423 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ValidSenderDomainHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ValidSenderDomainHandlerTest.java
@@ -31,7 +31,7 @@ import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookReturnCode;
 import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 import com.google.common.base.Preconditions;
 
@@ -103,7 +103,7 @@ public class ValidSenderDomainHandlerTest {
     
     // Test for JAMES-580
     @Test
-    public void testNullSenderNotReject() {
+    void testNullSenderNotReject() {
         ValidSenderDomainHandler handler = createHandler();
         HookReturnCode response = handler.doMail(setupMockedSession(null), MaybeSender.nullSender()).getResult();
         
@@ -111,7 +111,7 @@ public class ValidSenderDomainHandlerTest {
     }
 
     @Test
-    public void testInvalidSenderDomainReject() throws Exception {
+    void testInvalidSenderDomainReject() throws Exception {
         ValidSenderDomainHandler handler = createHandler();
         SMTPSession session = setupMockedSession(new MailAddress("invalid@invalid"));
         MaybeSender sender = session.getAttachment(SMTPSession.SENDER, State.Transaction).get();
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/hook/HookResultTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/hook/HookResultTest.java
index a76d50a..f7a0a2f 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/hook/HookResultTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/hook/HookResultTest.java
@@ -19,14 +19,14 @@
 
 package org.apache.james.protocols.smtp.hook;
 
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
 
 public class HookResultTest {
 
     @Test
-    public void shouldMatchBeanContract() {
+    void shouldMatchBeanContract() {
         EqualsVerifier.forClass(HookResult.class)
             .verify();
     }
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettySMTPSServerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettySMTPSServerTest.java
index b14b568..0289b32 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettySMTPSServerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettySMTPSServerTest.java
@@ -26,8 +26,8 @@ import org.apache.james.protocols.api.ProtocolServer;
 import org.apache.james.protocols.netty.NettyServer;
 import org.apache.james.protocols.smtp.AbstractSMTPSServerTest;
 import org.jboss.netty.util.HashedWheelTimer;
-import org.junit.After;
-import org.junit.Before;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 
 /**
  * Integration tests which use netty implementation
@@ -41,13 +41,13 @@ public class NettySMTPSServerTest extends AbstractSMTPSServerTest {
 
     private HashedWheelTimer hashedWheelTimer;
 
-    @Before
-    public void setup() {
+    @BeforeEach
+    void setup() {
         hashedWheelTimer = new HashedWheelTimer();
     }
 
-    @After
-    public void teardown() {
+    @AfterEach
+    void teardown() {
         hashedWheelTimer.stop();
     }
 
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettySMTPServerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettySMTPServerTest.java
index 3adeb44..d1bc8c5 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettySMTPServerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettySMTPServerTest.java
@@ -25,8 +25,8 @@ import org.apache.james.protocols.api.ProtocolServer;
 import org.apache.james.protocols.netty.NettyServer;
 import org.apache.james.protocols.smtp.AbstractSMTPServerTest;
 import org.jboss.netty.util.HashedWheelTimer;
-import org.junit.After;
-import org.junit.Before;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 
 /**
  * Integration tests which use netty implementation
@@ -40,13 +40,13 @@ public class NettySMTPServerTest extends AbstractSMTPServerTest {
 
     private HashedWheelTimer hashedWheelTimer;
 
-    @Before
-    public void setup() {
+    @BeforeEach
+    void setup() {
         hashedWheelTimer = new HashedWheelTimer();
     }
 
-    @After
-    public void teardown() {
+    @AfterEach
+    void teardown() {
         hashedWheelTimer.stop();
     }
 
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettyStartTlsSMTPServerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettyStartTlsSMTPServerTest.java
index b5edd0d..1b2a563 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettyStartTlsSMTPServerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/netty/NettyStartTlsSMTPServerTest.java
@@ -32,6 +32,8 @@ import javax.mail.Session;
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
 
+import com.sun.mail.smtp.SMTPTransport;
+
 import org.apache.commons.net.smtp.SMTPReply;
 import org.apache.commons.net.smtp.SMTPSClient;
 import org.apache.james.metrics.tests.RecordingMetricFactory;
@@ -53,11 +55,9 @@ import org.apache.james.protocols.smtp.SMTPProtocolHandlerChain;
 import org.apache.james.protocols.smtp.utils.TestMessageHook;
 import org.assertj.core.api.AssertDelegateTarget;
 import org.jboss.netty.util.HashedWheelTimer;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.sun.mail.smtp.SMTPTransport;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 public class NettyStartTlsSMTPServerTest {
 
@@ -68,13 +68,13 @@ public class NettyStartTlsSMTPServerTest {
     private ProtocolServer server = null;
     private HashedWheelTimer hashedWheelTimer;
 
-    @Before
-    public void setup() {
+    @BeforeEach
+    void setup() {
         hashedWheelTimer = new HashedWheelTimer();
     }
 
-    @After
-    public void tearDown() throws Exception {
+    @AfterEach
+    void tearDown() throws Exception {
         if (smtpsClient != null) {
             smtpsClient.disconnect();
         }
@@ -110,7 +110,7 @@ public class NettyStartTlsSMTPServerTest {
     }
 
     @Test
-    public void connectShouldReturnTrueWhenConnecting() throws Exception {
+    void connectShouldReturnTrueWhenConnecting() throws Exception {
         server = createServer(createProtocol(Optional.empty()), Encryption.createStartTls(BogusSslContextFactory.getServerContext()));
         smtpsClient = createClient();
 
@@ -121,7 +121,7 @@ public class NettyStartTlsSMTPServerTest {
     }
 
     @Test
-    public void ehloShouldReturnTrueWhenSendingTheCommand() throws Exception {
+    void ehloShouldReturnTrueWhenSendingTheCommand() throws Exception {
         server = createServer(createProtocol(Optional.empty()), Encryption.createStartTls(BogusSslContextFactory.getServerContext()));
         smtpsClient = createClient();
 
@@ -134,7 +134,7 @@ public class NettyStartTlsSMTPServerTest {
     }
 
     @Test
-    public void startTlsShouldBeAnnouncedWhenServerSupportsIt() throws Exception {
+    void startTlsShouldBeAnnouncedWhenServerSupportsIt() throws Exception {
         server = createServer(createProtocol(Optional.empty()), Encryption.createStartTls(BogusSslContextFactory.getServerContext()));
         smtpsClient = createClient();
 
@@ -163,7 +163,7 @@ public class NettyStartTlsSMTPServerTest {
     }
 
     @Test
-    public void startTlsShouldReturnTrueWhenServerSupportsIt() throws Exception {
+    void startTlsShouldReturnTrueWhenServerSupportsIt() throws Exception {
         server = createServer(createProtocol(Optional.empty()), Encryption.createStartTls(BogusSslContextFactory.getServerContext()));
         smtpsClient = createClient();
 
@@ -177,7 +177,7 @@ public class NettyStartTlsSMTPServerTest {
     }
 
     @Test
-    public void startTlsShouldFailWhenFollowedByInjectedCommand() throws Exception {
+    void startTlsShouldFailWhenFollowedByInjectedCommand() throws Exception {
         server = createServer(createProtocol(Optional.empty()), Encryption.createStartTls(BogusSslContextFactory.getServerContext()));
         smtpsClient = createClient();
 
@@ -191,7 +191,7 @@ public class NettyStartTlsSMTPServerTest {
     }
 
     @Test
-    public void startTlsShouldFailWhenFollowedByInjectedCommandAndNotAtBeginningOfLine() throws Exception {
+    void startTlsShouldFailWhenFollowedByInjectedCommandAndNotAtBeginningOfLine() throws Exception {
         server = createServer(createProtocol(Optional.empty()), Encryption.createStartTls(BogusSslContextFactory.getServerContext()));
         smtpsClient = createClient();
 
@@ -205,7 +205,7 @@ public class NettyStartTlsSMTPServerTest {
     }
 
     @Test
-    public void startTlsShouldWorkWhenUsingJavamail() throws Exception {
+    void startTlsShouldWorkWhenUsingJavamail() throws Exception {
         TestMessageHook hook = new TestMessageHook();
         server = createServer(createProtocol(Optional.<ProtocolHandler>of(hook)), Encryption.createStartTls(BogusSslContextFactory.getServerContext()));
         server.bind();


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


[james-project] 10/13: JAMES-3435 Serialization tests for eventsourcing ACL POJOs

Posted by bt...@apache.org.
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 9dc0a4c68e69cf2712d56239d2da16db2ba9db72
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sat Dec 5 09:34:35 2020 +0700

    JAMES-3435 Serialization tests for eventsourcing ACL POJOs
---
 .../mail/eventsourcing/acl/ACLUpdatedDTOTest.java  | 72 ++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTOTest.java
new file mode 100644
index 0000000..76c1080
--- /dev/null
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTOTest.java
@@ -0,0 +1,72 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import org.apache.james.JsonSerializationVerifier;
+import org.apache.james.eventsourcing.EventId;
+import org.apache.james.mailbox.acl.ACLDiff;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.exception.UnsupportedRightException;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.junit.jupiter.api.Test;
+
+class ACLUpdatedDTOTest {
+    private static final String JSON = "{" +
+        "  \"eventId\":0," +
+        "  \"aggregateKey\":\"e22b3ac0-a80b-11e7-bb00-777268d65503\"," +
+        "  \"type\":\"acl-updated\"," +
+        "  \"aclDiff\":{" +
+        "    \"oldAcl\":{\"entries\":{\"$any\":\"a\"}}," +
+        "    \"newAcl\":{\"entries\":{\"$any\":\"l\"}}" +
+        "  }" +
+        "}";
+    private static final MailboxACL.EntryKey ENTRY_KEY = MailboxACL.EntryKey.createGroupEntryKey("any", false);
+    private static final MailboxACL.Rfc4314Rights RIGHTS = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Administer);
+    private static final ACLUpdated EVENT = aclUpdated();
+
+    private static ACLUpdated aclUpdated() {
+        try {
+            MailboxACL oldACL = MailboxACL.EMPTY.apply(
+                MailboxACL.command()
+                    .key(ENTRY_KEY)
+                    .rights(RIGHTS)
+                    .asAddition());
+            MailboxACL newAcl = MailboxACL.EMPTY.apply(
+                MailboxACL.command()
+                    .key(ENTRY_KEY)
+                    .rights(MailboxACL.Right.Lookup)
+                    .asAddition());
+            return new ACLUpdated(
+                new MailboxAggregateId(CassandraId.of("e22b3ac0-a80b-11e7-bb00-777268d65503")),
+                EventId.first(),
+                ACLDiff.computeDiff(oldACL, newAcl));
+        } catch (UnsupportedRightException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Test
+    void shouldMatchSerializableContract() throws Exception {
+        JsonSerializationVerifier.dtoModule(ACLModule.ACL_UPDATE)
+            .bean(EVENT)
+            .json(JSON)
+            .verify();
+    }
+}
\ No newline at end of file


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


[james-project] 13/13: JAMES 3400 Add Jwt Option

Posted by bt...@apache.org.
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 bce3fb8b3f56e6900f007ef9f745049d49854071
Author: quanth <hq...@linagora.com>
AuthorDate: Mon Nov 23 13:57:28 2020 +0700

    JAMES 3400 Add Jwt Option
---
 .../java/org/apache/james/cli/WebAdminCli.java     |  24 +++
 .../org/apache/james/cli/domain/DomainCommand.java |   5 +
 .../james/cli/domain/DomainCreateCommand.java      |   4 +-
 .../james/cli/domain/DomainDeleteCommand.java      |   4 +-
 .../james/cli/domain/DomainExistCommand.java       |   4 +-
 .../apache/james/cli/domain/DomainListCommand.java |   6 +-
 .../org/apache/james/cli/user/UserCommand.java     |   5 +
 .../apache/james/cli/user/UserCreateCommand.java   |   6 +-
 .../apache/james/cli/user/UserDeleteCommand.java   |   4 +-
 .../apache/james/cli/user/UserExistCommand.java    |   4 +-
 .../org/apache/james/cli/user/UserListCommand.java |   6 +-
 .../james/httpclient/FeignClientFactory.java       |  79 +++++++++
 .../UserCommand.java => httpclient/JwtToken.java}  |  46 ++----
 .../java/org/apache/james/cli/JwtOptionTest.java   | 178 +++++++++++++++++++++
 .../src/test/resources/valid_token_admin_false.jwt |   5 +
 .../src/test/resources/valid_token_admin_true.jwt  |   5 +
 16 files changed, 324 insertions(+), 61 deletions(-)

diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/WebAdminCli.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/WebAdminCli.java
index 7efdebd..71d20bb 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/WebAdminCli.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/WebAdminCli.java
@@ -20,11 +20,17 @@
 package org.apache.james.cli;
 
 import java.io.PrintStream;
+import java.util.Optional;
 import java.util.concurrent.Callable;
 
 import org.apache.james.cli.domain.DomainCommand;
 import org.apache.james.cli.user.UserCommand;
+import org.apache.james.httpclient.FeignClientFactory;
+import org.apache.james.httpclient.JwtToken;
 
+import feign.Feign;
+import feign.jackson.JacksonDecoder;
+import feign.jackson.JacksonEncoder;
 import picocli.CommandLine;
 
 @CommandLine.Command(
@@ -41,6 +47,16 @@ public class WebAdminCli implements Callable<Integer> {
         defaultValue = "http://127.0.0.1:8000")
     String jamesUrl;
 
+    public @CommandLine.Option(
+        names = "--jwt-token",
+        description = "Authentication Token")
+    String jwt;
+
+    public @CommandLine.Option(
+        names = "--jwt-from-file",
+        description = "Authentication Token from a file")
+    String jwtFilePath;
+
     @Override
     public Integer call() {
         return CLI_FINISHED_SUCCEED;
@@ -66,4 +82,12 @@ public class WebAdminCli implements Callable<Integer> {
         return execute(out, err, args);
     }
 
+    public Feign.Builder feignClientFactory(PrintStream err) {
+        return new FeignClientFactory(new JwtToken(Optional.ofNullable(jwt),
+            Optional.ofNullable(jwtFilePath), err))
+            .builder()
+            .decoder(new JacksonDecoder())
+            .encoder(new JacksonEncoder());
+    }
+
 }
\ No newline at end of file
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainCommand.java
index 209fb95..ec38083 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainCommand.java
@@ -23,6 +23,7 @@ import java.io.PrintStream;
 import java.util.concurrent.Callable;
 
 import org.apache.james.cli.WebAdminCli;
+import org.apache.james.httpclient.DomainClient;
 
 import picocli.CommandLine;
 
@@ -52,4 +53,8 @@ public class DomainCommand implements Callable<Integer> {
         return WebAdminCli.CLI_FINISHED_SUCCEED;
     }
 
+    public DomainClient fullyQualifiedURL(String partOfUrl) {
+        return webAdminCli.feignClientFactory(err).target(DomainClient.class, webAdminCli.jamesUrl + partOfUrl);
+    }
+
 }
\ No newline at end of file
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainCreateCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainCreateCommand.java
index 5b75b00..af0b074 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainCreateCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainCreateCommand.java
@@ -24,7 +24,6 @@ import java.util.concurrent.Callable;
 import org.apache.james.cli.WebAdminCli;
 import org.apache.james.httpclient.DomainClient;
 
-import feign.Feign;
 import feign.Response;
 import picocli.CommandLine;
 
@@ -43,8 +42,7 @@ public class DomainCreateCommand implements Callable<Integer> {
     @Override
     public Integer call() {
         try {
-            DomainClient domainClient = Feign.builder()
-                .target(DomainClient.class, domainCommand.webAdminCli.jamesUrl + "/domains");
+            DomainClient domainClient = domainCommand.fullyQualifiedURL("/domains");
             Response rs = domainClient.createADomain(domainName);
             if (rs.status() == CREATED_CODE) {
                 return WebAdminCli.CLI_FINISHED_SUCCEED;
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainDeleteCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainDeleteCommand.java
index 11853fd..af2115e 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainDeleteCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainDeleteCommand.java
@@ -24,7 +24,6 @@ import java.util.concurrent.Callable;
 import org.apache.james.cli.WebAdminCli;
 import org.apache.james.httpclient.DomainClient;
 
-import feign.Feign;
 import feign.Response;
 import picocli.CommandLine;
 
@@ -43,8 +42,7 @@ public class DomainDeleteCommand implements Callable<Integer> {
     @Override
     public Integer call() {
         try {
-            DomainClient domainClient = Feign.builder()
-                .target(DomainClient.class, domainCommand.webAdminCli.jamesUrl + "/domains");
+            DomainClient domainClient = domainCommand.fullyQualifiedURL("/domains");
             Response rs = domainClient.deleteADomain(domainName);
             if (rs.status() == DELETED_CODE) {
                 return WebAdminCli.CLI_FINISHED_SUCCEED;
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainExistCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainExistCommand.java
index be39c31..094c16b 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainExistCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainExistCommand.java
@@ -24,7 +24,6 @@ import java.util.concurrent.Callable;
 import org.apache.james.cli.WebAdminCli;
 import org.apache.james.httpclient.DomainClient;
 
-import feign.Feign;
 import feign.Response;
 import picocli.CommandLine;
 
@@ -44,8 +43,7 @@ public class DomainExistCommand implements Callable<Integer> {
     @Override
     public Integer call() {
         try {
-            DomainClient domainClient = Feign.builder()
-                .target(DomainClient.class, domainCommand.webAdminCli.jamesUrl + "/domains");
+            DomainClient domainClient = domainCommand.fullyQualifiedURL("/domains");
             Response rs = domainClient.doesExist(domainName);
             if (rs.status() == EXISTED_CODE) {
                 domainCommand.out.println(domainName + " exists");
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainListCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainListCommand.java
index ef4ab43..e8d00fd 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainListCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/domain/DomainListCommand.java
@@ -24,8 +24,6 @@ import java.util.concurrent.Callable;
 import org.apache.james.cli.WebAdminCli;
 import org.apache.james.httpclient.DomainClient;
 
-import feign.Feign;
-import feign.jackson.JacksonDecoder;
 import picocli.CommandLine;
 
 @CommandLine.Command(
@@ -38,9 +36,7 @@ public class DomainListCommand implements Callable<Integer> {
     @Override
     public Integer call() {
         try {
-            DomainClient domainClient = Feign.builder()
-                    .decoder(new JacksonDecoder())
-                    .target(DomainClient.class, domainCommand.webAdminCli.jamesUrl + "/domains");
+            DomainClient domainClient = domainCommand.fullyQualifiedURL("/domains");
             domainClient.getDomainList().forEach(domainCommand.out::println);
             return WebAdminCli.CLI_FINISHED_SUCCEED;
         } catch (Exception e) {
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCommand.java
index 6e27b3d..7d75f55 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCommand.java
@@ -23,6 +23,7 @@ import java.io.PrintStream;
 import java.util.concurrent.Callable;
 
 import org.apache.james.cli.WebAdminCli;
+import org.apache.james.httpclient.UserClient;
 
 import picocli.CommandLine;
 
@@ -52,4 +53,8 @@ public class UserCommand implements Callable<Integer> {
         return WebAdminCli.CLI_FINISHED_SUCCEED;
     }
 
+    public UserClient fullyQualifiedURL(String partOfUrl) {
+        return webAdminCli.feignClientFactory(err).target(UserClient.class, webAdminCli.jamesUrl + partOfUrl);
+    }
+
 }
\ No newline at end of file
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCreateCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCreateCommand.java
index 7c0cd52..f694ed3 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCreateCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCreateCommand.java
@@ -25,9 +25,7 @@ import org.apache.james.cli.WebAdminCli;
 import org.apache.james.httpclient.UserClient;
 import org.apache.james.httpclient.model.UserPassword;
 
-import feign.Feign;
 import feign.Response;
-import feign.jackson.JacksonEncoder;
 import picocli.CommandLine;
 
 @CommandLine.Command(
@@ -49,9 +47,7 @@ public class UserCreateCommand implements Callable<Integer> {
     @Override
     public Integer call() {
         try {
-            UserClient userClient = Feign.builder()
-                .encoder(new JacksonEncoder())
-                .target(UserClient.class, userCommand.webAdminCli.jamesUrl + "/users");
+            UserClient userClient = userCommand.fullyQualifiedURL("/users");
             Response rs = userClient.createAUser(userName, new UserPassword(new String(password)));
             if (rs.status() == CREATED_CODE) {
                 userCommand.out.println("The user was created successfully");
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserDeleteCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserDeleteCommand.java
index b5adab1..2578c01 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserDeleteCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserDeleteCommand.java
@@ -24,7 +24,6 @@ import java.util.concurrent.Callable;
 import org.apache.james.cli.WebAdminCli;
 import org.apache.james.httpclient.UserClient;
 
-import feign.Feign;
 import feign.Response;
 import picocli.CommandLine;
 
@@ -42,8 +41,7 @@ public class UserDeleteCommand implements Callable<Integer> {
     @Override
     public Integer call() {
         try {
-            UserClient userClient = Feign.builder()
-                .target(UserClient.class, userCommand.webAdminCli.jamesUrl + "/users");
+            UserClient userClient = userCommand.fullyQualifiedURL("/users");
             Response rs = userClient.deleteAUser(userName);
             if (rs.status() == DELETED_CODE) {
                 return WebAdminCli.CLI_FINISHED_SUCCEED;
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserExistCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserExistCommand.java
index 5d4b391..e7eb91f 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserExistCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserExistCommand.java
@@ -24,7 +24,6 @@ import java.util.concurrent.Callable;
 import org.apache.james.cli.WebAdminCli;
 import org.apache.james.httpclient.UserClient;
 
-import feign.Feign;
 import feign.Response;
 import picocli.CommandLine;
 
@@ -44,8 +43,7 @@ public class UserExistCommand implements Callable<Integer> {
     @Override
     public Integer call() {
         try {
-            UserClient userClient = Feign.builder()
-                .target(UserClient.class, userCommand.webAdminCli.jamesUrl + "/users");
+            UserClient userClient = userCommand.fullyQualifiedURL("/users");
             Response rs = userClient.doesExist(userName);
             if (rs.status() == EXISTED_CODE) {
                 userCommand.out.println(userName + " exists");
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserListCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserListCommand.java
index 9e2b0d7..3ad46e1 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserListCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserListCommand.java
@@ -24,8 +24,6 @@ import java.util.concurrent.Callable;
 import org.apache.james.cli.WebAdminCli;
 import org.apache.james.httpclient.UserClient;
 
-import feign.Feign;
-import feign.jackson.JacksonDecoder;
 import picocli.CommandLine;
 
 @CommandLine.Command(
@@ -38,9 +36,7 @@ public class UserListCommand implements Callable<Integer> {
     @Override
     public Integer call() {
         try {
-            UserClient userClient = Feign.builder()
-                .decoder(new JacksonDecoder())
-                .target(UserClient.class, userCommand.webAdminCli.jamesUrl + "/users");
+            UserClient userClient = userCommand.fullyQualifiedURL("/users");
             userClient.getUserNameList().forEach(userName -> userCommand.out.println(userName.getUserName()));
             return WebAdminCli.CLI_FINISHED_SUCCEED;
         } catch (Exception e) {
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/FeignClientFactory.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/FeignClientFactory.java
new file mode 100644
index 0000000..9a80b26
--- /dev/null
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/FeignClientFactory.java
@@ -0,0 +1,79 @@
+/******************************************************************
+ * 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.httpclient;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Scanner;
+
+import feign.Feign;
+
+public class FeignClientFactory {
+
+    private final JwtToken jwtToken;
+
+    public FeignClientFactory(JwtToken jwtToken) {
+        this.jwtToken = jwtToken;
+    }
+
+    public Feign.Builder builder() {
+        return jwtOptionsHandler();
+    }
+
+    private Feign.Builder jwtOptionsHandler() {
+        return jwtToken.jwtTokenString
+            .map(tokenString -> jwtToken.jwtFilePath
+                .map(tokenFile -> jwtTokenAndJwtFileAreBothPresentHandler())
+                .orElse(jwtTokenIsPresentAndJwtFromFileIsNotPresentHandler(tokenString)))
+            .orElse(jwtToken.jwtFilePath
+                .map(this::jwtTokenIsNotPresentAndJwtFromFileIsPresentHandler)
+                .orElse(jwtTokenAndJwtFromFileAreNotPresentHandler()));
+    }
+
+    private Feign.Builder jwtTokenAndJwtFileAreBothPresentHandler() {
+        jwtToken.err.println("Cannot specify both --jwt-from-file and --jwt-token options.");
+        return Feign.builder();
+    }
+
+    private Feign.Builder jwtTokenIsPresentAndJwtFromFileIsNotPresentHandler(String tokenString) {
+        return Feign.builder()
+            .requestInterceptor(requestTemplate -> requestTemplate.header("Authorization", "Bearer " + tokenString));
+    }
+
+    private Feign.Builder jwtTokenIsNotPresentAndJwtFromFileIsPresentHandler(String tokenFile) {
+        File myObj = new File(tokenFile);
+        try (Scanner myReader = new Scanner(myObj)) {
+            StringBuilder data = new StringBuilder();
+            while (myReader.hasNextLine()) {
+                data.append(myReader.nextLine());
+            }
+            return Feign.builder()
+                .requestInterceptor(requestTemplate -> requestTemplate.header("Authorization", "Bearer " + data.toString()));
+        } catch (FileNotFoundException e) {
+            e.printStackTrace(jwtToken.err);
+            return Feign.builder();
+        }
+    }
+
+    private Feign.Builder jwtTokenAndJwtFromFileAreNotPresentHandler() {
+        return Feign.builder();
+    }
+
+}
diff --git a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCommand.java b/server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/JwtToken.java
similarity index 61%
copy from server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCommand.java
copy to server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/JwtToken.java
index 6e27b3d..ad23364 100644
--- a/server/protocols/webadmin-cli/src/main/java/org/apache/james/cli/user/UserCommand.java
+++ b/server/protocols/webadmin-cli/src/main/java/org/apache/james/httpclient/JwtToken.java
@@ -17,39 +17,23 @@
  * under the License.                                             *
  ******************************************************************/
 
-package org.apache.james.cli.user;
+package org.apache.james.httpclient;
 
 import java.io.PrintStream;
-import java.util.concurrent.Callable;
-
-import org.apache.james.cli.WebAdminCli;
-
-import picocli.CommandLine;
-
-@CommandLine.Command(
-    name = "user",
-    description = "Manage Users",
-    subcommands = {
-        UserListCommand.class,
-        UserCreateCommand.class,
-        UserDeleteCommand.class,
-        UserExistCommand.class
-    })
-public class UserCommand implements Callable<Integer> {
-
-    protected final WebAdminCli webAdminCli;
-    protected final PrintStream out;
-    protected final PrintStream err;
-
-    public UserCommand(PrintStream out, WebAdminCli webAdminCli, PrintStream err) {
-        this.out = out;
-        this.webAdminCli = webAdminCli;
-        this.err = err;
-    }
+import java.util.Optional;
+
+public class JwtToken {
+
+    final Optional<String> jwtTokenString;
 
-    @Override
-    public Integer call() {
-        return WebAdminCli.CLI_FINISHED_SUCCEED;
+    final Optional<String> jwtFilePath;
+
+    PrintStream err;
+
+    public JwtToken(Optional<String> jwtTokenString, Optional<String> jwtFilePath, PrintStream err) {
+        this.jwtTokenString = jwtTokenString;
+        this.jwtFilePath = jwtFilePath;
+        this.err = err;
     }
 
-}
\ No newline at end of file
+}
diff --git a/server/protocols/webadmin-cli/src/test/java/org/apache/james/cli/JwtOptionTest.java b/server/protocols/webadmin-cli/src/test/java/org/apache/james/cli/JwtOptionTest.java
new file mode 100644
index 0000000..65841d2
--- /dev/null
+++ b/server/protocols/webadmin-cli/src/test/java/org/apache/james/cli/JwtOptionTest.java
@@ -0,0 +1,178 @@
+/******************************************************************
+ * 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.cli;
+
+import static org.apache.james.MemoryJamesServerMain.IN_MEMORY_SERVER_AGGREGATE_MODULE;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Optional;
+
+import org.apache.james.GuiceJamesServer;
+import org.apache.james.JamesServerBuilder;
+import org.apache.james.JamesServerExtension;
+import org.apache.james.jwt.JwtConfiguration;
+import org.apache.james.jwt.JwtTokenVerifier;
+import org.apache.james.util.ClassLoaderUtils;
+import org.apache.james.util.Port;
+import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.WebAdminGuiceProbe;
+import org.apache.james.webadmin.authentication.AuthenticationFilter;
+import org.apache.james.webadmin.authentication.JwtFilter;
+import org.apache.james.webadmin.integration.WebadminIntegrationTestModule;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import com.google.inject.name.Names;
+
+public class JwtOptionTest {
+
+    @RegisterExtension
+    static JamesServerExtension jamesServerExtension = new JamesServerBuilder<>(JamesServerBuilder.defaultConfigurationProvider())
+        .server(configuration -> GuiceJamesServer.forConfiguration(configuration)
+            .combineWith(IN_MEMORY_SERVER_AGGREGATE_MODULE)
+            .overrideWith(new WebadminIntegrationTestModule())
+            .overrideWith(binder -> binder.bind(AuthenticationFilter.class).to(JwtFilter.class))
+            .overrideWith(binder -> binder.bind(JwtTokenVerifier.Factory.class)
+                .annotatedWith(Names.named("webadmin"))
+                .toInstance(() -> JwtTokenVerifier.create(jwtConfiguration()))))
+        .build();
+
+    protected static JwtConfiguration jwtConfiguration() {
+        return new JwtConfiguration(
+            Optional.of(ClassLoaderUtils.getSystemResourceAsString("jwt_publickey")));
+    }
+
+    private static final String VALID_TOKEN_ADMIN_TRUE = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbkBvcGVuL" +
+        "XBhYXMub3JnIiwiYWRtaW4iOnRydWUsImlhdCI6MTQ4OTAzODQzOH0.rgxCkdWEa-92a4R-72a9Z49k4LRvQDShgci5Y7qWRUP9IGJCK-lMkrHF" +
+        "4H0a6L87BYppxVW701zaZ6dNxRMvHnjLBBWnPsC2B0rkkr2hEL2zfz7sb-iNGV-J4ICx97t8-TfQ5rz3VOX0FwdusPL_rJtmlGEGRivPkR6_aBe1" +
+        "kQnvMlwpqF_3ox58EUqYJk6lK_6rjKEV3Xfre31IMpuQUy6c7TKc95sL2-13cknelTierBEmZ00RzTtv9SHIEfzZTfaUK2Wm0PvnQjmU2nIdEvU" +
+        "EqE-jrM3yYXcQzoO-YTQnEhdl-iqbCfmEpYkl2Bx3eIq7gRxxnr7BPsX6HrCB0w";
+
+    private static final String VALID_TOKEN_ADMIN_FALSE = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbkBvcGVu" +
+        "LXBhYXMub3JnIiwiYWRtaW4iOmZhbHNlLCJpYXQiOjE0ODkwNDA4Njd9.reQc3DiVvbQHF08oW1qOUyDJyv3tfzDNk8jhVZequiCdOI9vXnRlOe" +
+        "-yDYktd4WT8MYhqY7MgS-wR0vO9jZFv8ZCgd_MkKCvCO0HmMjP5iQPZ0kqGkgWUH7X123tfR38MfbCVAdPDba-K3MfkogV1xvDhlkPScFr_6MxE" +
+        "xtedOK2JnQZn7t9sUzSrcyjWverm7gZkPptkIVoS8TsEeMMME5vFXe_nqkEG69q3kuBUm_33tbR5oNS0ZGZKlG9r41lHBjyf9J1xN4UYV8n866d" +
+        "a7RPPCzshIWUtO0q9T2umWTnp-6OnOdBCkndrZmRR6pPxsD5YL0_77Wq8KT_5__fGA";
+
+    private static final String PATH_OF_VALID_TOKEN_ADMIN_TRUE_FILE = "src/test/resources/valid_token_admin_true.jwt";
+    private static final String PATH_OF_VALID_TOKEN_ADMIN_FALSE_FILE = "src/test/resources/valid_token_admin_false.jwt";
+    private static final String PATH_OF_INVALID_JWT_FILE = "src/test/resources/keystore";
+
+    private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();
+    private final ByteArrayOutputStream errorStreamCaptor = new ByteArrayOutputStream();
+
+    private DataProbeImpl dataProbe;
+
+    @Test
+    void jwtTokenWithAdminTrueAndNonPresentJwtFileShouldPassAuthentication(GuiceJamesServer server) throws Exception {
+        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
+        dataProbe = server.getProbe(DataProbeImpl.class);
+
+        int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
+            "--url", "http://127.0.0.1:" + port.getValue(), "--jwt-token", VALID_TOKEN_ADMIN_TRUE, "domain", "create", "linagora.com");
+
+        assertThat(exitCode).isEqualTo(0);
+        assertThat(dataProbe.listDomains()).contains("linagora.com");
+    }
+
+    @Test
+    void jwtTokenWithAdminFalseAndNonPresentJwtFileShouldRejectRequests(GuiceJamesServer server) {
+        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
+        dataProbe = server.getProbe(DataProbeImpl.class);
+
+        int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
+            "--url", "http://127.0.0.1:" + port.getValue(), "--jwt-token", VALID_TOKEN_ADMIN_FALSE, "domain", "create", "linagora.com");
+
+        assertThat(exitCode).isEqualTo(1);
+    }
+
+    @Test
+    void jwtFromFileWithAdminTrueAndNonPresentJwtTokenShouldPassAuthentication(GuiceJamesServer server) throws Exception {
+        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
+        dataProbe = server.getProbe(DataProbeImpl.class);
+
+        int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
+            "--url", "http://127.0.0.1:" + port.getValue(), "--jwt-from-file", PATH_OF_VALID_TOKEN_ADMIN_TRUE_FILE, "domain", "create", "linagora.com");
+
+        assertThat(exitCode).isEqualTo(0);
+        assertThat(dataProbe.listDomains()).contains("linagora.com");
+    }
+
+    @Test
+    void jwtFromFileWithAdminFalseAndNonPresentJwtTokenShouldRejectRequests(GuiceJamesServer server) {
+        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
+        dataProbe = server.getProbe(DataProbeImpl.class);
+
+        int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
+            "--url", "http://127.0.0.1:" + port.getValue(), "--jwt-from-file", PATH_OF_VALID_TOKEN_ADMIN_FALSE_FILE, "domain", "create", "linagora.com");
+
+        assertThat(exitCode).isEqualTo(1);
+    }
+
+    @Test
+    void jwtFromFileWithNonExistingFileShouldThrowFileNotFoundException(GuiceJamesServer server) {
+        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
+        dataProbe = server.getProbe(DataProbeImpl.class);
+
+        int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
+            "--url", "http://127.0.0.1:" + port.getValue(), "--jwt-from-file", "", "domain", "create", "linagora.com");
+
+        assertThat(exitCode).isEqualTo(1);
+        assertThat(errorStreamCaptor.toString()).contains("FileNotFoundException");
+    }
+
+    @Test
+    void jwtFromFileWithInvalidFileShouldRejectRequests(GuiceJamesServer server) {
+        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
+        dataProbe = server.getProbe(DataProbeImpl.class);
+
+        int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
+            "--url", "http://127.0.0.1:" + port.getValue(), "--jwt-from-file", PATH_OF_INVALID_JWT_FILE, "domain", "create", "linagora.com");
+
+        assertThat(exitCode).isEqualTo(1);
+    }
+
+    @Test
+    void jwtTokenAndJwtFileAreBothPresentShouldFailAuthentication(GuiceJamesServer server) {
+        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
+        dataProbe = server.getProbe(DataProbeImpl.class);
+
+        int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
+            "--url", "http://127.0.0.1:" + port.getValue(), "--jwt-from-file", PATH_OF_VALID_TOKEN_ADMIN_TRUE_FILE,
+            "--jwt-token", VALID_TOKEN_ADMIN_TRUE, "domain", "list");
+
+        assertThat(exitCode).isEqualTo(1);
+        assertThat(errorStreamCaptor.toString()).contains("Cannot specify both --jwt-from-file and --jwt-token options.");
+    }
+
+    @Test
+    void jwtTokenAndJwtFileAreNotPresentShouldRejectRequests(GuiceJamesServer server) {
+        Port port = server.getProbe(WebAdminGuiceProbe.class).getWebAdminPort();
+        dataProbe = server.getProbe(DataProbeImpl.class);
+
+        int exitCode = WebAdminCli.executeFluent(new PrintStream(outputStreamCaptor), new PrintStream(errorStreamCaptor),
+            "--url", "http://127.0.0.1:" + port.getValue(), "domain", "create", "linagora.com");
+
+        assertThat(exitCode).isEqualTo(1);
+    }
+
+}
diff --git a/server/protocols/webadmin-cli/src/test/resources/valid_token_admin_false.jwt b/server/protocols/webadmin-cli/src/test/resources/valid_token_admin_false.jwt
new file mode 100644
index 0000000..2e1befa
--- /dev/null
+++ b/server/protocols/webadmin-cli/src/test/resources/valid_token_admin_false.jwt
@@ -0,0 +1,5 @@
+eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbkBvcGVu
+LXBhYXMub3JnIiwiYWRtaW4iOmZhbHNlLCJpYXQiOjE0ODkwNDA4Njd9.reQc3DiVvbQHF08oW1qOUyDJyv3tfzDNk8jhVZequiCdOI9vXnRlOe
+-yDYktd4WT8MYhqY7MgS-wR0vO9jZFv8ZCgd_MkKCvCO0HmMjP5iQPZ0kqGkgWUH7X123tfR38MfbCVAdPDba-K3MfkogV1xvDhlkPScFr_6MxE
+xtedOK2JnQZn7t9sUzSrcyjWverm7gZkPptkIVoS8TsEeMMME5vFXe_nqkEG69q3kuBUm_33tbR5oNS0ZGZKlG9r41lHBjyf9J1xN4UYV8n866d
+a7RPPCzshIWUtO0q9T2umWTnp-6OnOdBCkndrZmRR6pPxsD5YL0_77Wq8KT_5__fGA
\ No newline at end of file
diff --git a/server/protocols/webadmin-cli/src/test/resources/valid_token_admin_true.jwt b/server/protocols/webadmin-cli/src/test/resources/valid_token_admin_true.jwt
new file mode 100644
index 0000000..71a623e
--- /dev/null
+++ b/server/protocols/webadmin-cli/src/test/resources/valid_token_admin_true.jwt
@@ -0,0 +1,5 @@
+eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbkBvcGVuL
+XBhYXMub3JnIiwiYWRtaW4iOnRydWUsImlhdCI6MTQ4OTAzODQzOH0.rgxCkdWEa-92a4R-72a9Z49k4LRvQDShgci5Y7qWRUP9IGJCK-lMkrHF
+4H0a6L87BYppxVW701zaZ6dNxRMvHnjLBBWnPsC2B0rkkr2hEL2zfz7sb-iNGV-J4ICx97t8-TfQ5rz3VOX0FwdusPL_rJtmlGEGRivPkR6_aBe1
+kQnvMlwpqF_3ox58EUqYJk6lK_6rjKEV3Xfre31IMpuQUy6c7TKc95sL2-13cknelTierBEmZ00RzTtv9SHIEfzZTfaUK2Wm0PvnQjmU2nIdEvU
+EqE-jrM3yYXcQzoO-YTQnEhdl-iqbCfmEpYkl2Bx3eIq7gRxxnr7BPsX6HrCB0w
\ No newline at end of file


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


[james-project] 05/13: JAMES-3435 User rights DAO was not cleared upon ACL deletes

Posted by bt...@apache.org.
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 46e0a296ad8635ff1cba66335b55a9a7444637d2
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Dec 3 07:40:37 2020 +0700

    JAMES-3435 User rights DAO was not cleared upon ACL deletes
---
 .../org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java   | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
index d9c8123..517256e 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
@@ -77,6 +77,8 @@ public class CassandraACLMapper {
     }
 
     public Mono<Void> delete(CassandraId cassandraId) {
-        return aclDao().flatMap(dao -> dao.delete(cassandraId));
+        return aclDao().flatMap(dao -> dao.getACL(cassandraId)
+            .flatMap(acl -> userMailboxRightsDAO.update(cassandraId, ACLDiff.computeDiff(acl, MailboxACL.EMPTY))
+            .then(dao.delete(cassandraId))));
     }
 }


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


[james-project] 04/13: JAMES-3435 Migration task for CassandraACLDAOV2 adoption

Posted by bt...@apache.org.
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 461d1c657b6ac78266eed28eebf26244cb191fa9
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Dec 2 14:21:40 2020 +0700

    JAMES-3435 Migration task for CassandraACLDAOV2 adoption
---
 .../versions/CassandraSchemaVersionManager.java    |   2 +-
 .../mailbox/cassandra/mail/CassandraACLDAOV2.java  |   3 +-
 .../mailbox/cassandra/mail/CassandraACLMapper.java |  37 +++++--
 .../cassandra/mail/migration/AclV2Migration.java   | 115 +++++++++++++++++++++
 ...AclV2MigrationTaskAdditionalInformationDTO.java |  69 +++++++++++++
 .../mail/migration/AclV2MigrationTaskDTO.java      |  59 +++++++++++
 .../cassandra/CassandraMailboxManagerTest.java     |   7 +-
 .../cassandra/mail/CassandraACLMapperContract.java |   8 +-
 .../cassandra/mail/CassandraACLMapperV1Test.java   |  34 +++---
 .../cassandra/mail/CassandraACLMapperV2Test.java   |  36 ++++---
 .../cassandra/mail/CassandraMailboxMapperTest.java |   4 +-
 .../AclV2MigrationTaskSerializationTest.java       |  52 ++++++++++
 .../mail/migration/AclV2MigrationTest.java         | 112 ++++++++++++++++++++
 .../mail/migration/MailboxPathV2MigrationTest.java |   5 +-
 .../modules/mailbox/CassandraMailboxModule.java    |   2 +
 .../modules/webadmin/CassandraRoutesModule.java    |   3 +
 16 files changed, 500 insertions(+), 48 deletions(-)

diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java
index 29dae94..992c579 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java
@@ -36,7 +36,7 @@ import reactor.core.publisher.Mono;
 
 public class CassandraSchemaVersionManager {
     public static final SchemaVersion MIN_VERSION = new SchemaVersion(5);
-    public static final SchemaVersion MAX_VERSION = new SchemaVersion(9);
+    public static final SchemaVersion MAX_VERSION = new SchemaVersion(10);
     public static final SchemaVersion DEFAULT_VERSION = MIN_VERSION;
 
     private static final Logger LOGGER = LoggerFactory.getLogger(CassandraSchemaVersionManager.class);
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
index 9bc2ad3..c9e6339 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
@@ -136,6 +136,7 @@ public class CassandraACLDAOV2 implements CassandraACLDAO {
 
     public Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
         return getACL(cassandraId)
+            .switchIfEmpty(Mono.just(MailboxACL.EMPTY))
             .flatMap(oldACL -> delete(cassandraId)
                 .then(Flux.fromIterable(mailboxACL.getEntries().entrySet())
                     .concatMap(entry -> doSetACL(cassandraId, mailboxACL))
@@ -174,7 +175,7 @@ public class CassandraACLDAOV2 implements CassandraACLDAO {
             .collect(Guavate.toImmutableSet());
     }
 
-    private Mono<Void> doSetACL(CassandraId cassandraId, MailboxACL mailboxACL) {
+    public Mono<Void> doSetACL(CassandraId cassandraId, MailboxACL mailboxACL) {
         BatchStatement batchStatement = new BatchStatement();
         mailboxACL.getEntries().entrySet()
             .stream().map(entry -> replaceRights.bind()
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
index 7a6e1a8..d9c8123 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
@@ -21,6 +21,8 @@ package org.apache.james.mailbox.cassandra.mail;
 
 import javax.inject.Inject;
 
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.exception.MailboxException;
@@ -29,35 +31,52 @@ import org.apache.james.mailbox.model.MailboxACL;
 import reactor.core.publisher.Mono;
 
 public class CassandraACLMapper {
+    public static final SchemaVersion ACL_V2_SCHEME_VERSION = new SchemaVersion(10);
     private final CassandraUserMailboxRightsDAO userMailboxRightsDAO;
-    private final CassandraACLDAO cassandraACLDAO;
+    private final CassandraACLDAOV1 cassandraACLDAOV1;
+    private final CassandraACLDAOV2 cassandraACLDAOV2;
+    private final CassandraSchemaVersionManager versionManager;
 
     @Inject
     public CassandraACLMapper(CassandraUserMailboxRightsDAO userMailboxRightsDAO,
-                              CassandraACLDAO cassandraACLDAO) {
-        this.cassandraACLDAO = cassandraACLDAO;
+                              CassandraACLDAOV1 cassandraACLDAOV1,
+                              CassandraACLDAOV2 cassandraACLDAOV2,
+                              CassandraSchemaVersionManager versionManager) {
+        this.cassandraACLDAOV1 = cassandraACLDAOV1;
+        this.cassandraACLDAOV2 = cassandraACLDAOV2;
         this.userMailboxRightsDAO = userMailboxRightsDAO;
+        this.versionManager = versionManager;
+    }
+
+    private Mono<CassandraACLDAO> aclDao() {
+        return versionManager.isBefore(ACL_V2_SCHEME_VERSION)
+            .map(isBefore -> {
+                if (isBefore) {
+                    return cassandraACLDAOV1;
+                }
+                return cassandraACLDAOV2;
+            });
     }
 
     public Mono<MailboxACL> getACL(CassandraId cassandraId) {
-        return cassandraACLDAO.getACL(cassandraId);
+        return aclDao().flatMap(dao -> dao.getACL(cassandraId));
     }
 
     public Mono<ACLDiff> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
-        return cassandraACLDAO.updateACL(cassandraId, command)
+        return aclDao().flatMap(dao -> dao.updateACL(cassandraId, command)
             .flatMap(aclDiff -> userMailboxRightsDAO.update(cassandraId, aclDiff)
             .thenReturn(aclDiff))
-            .switchIfEmpty(Mono.error(new MailboxException("Unable to update ACL")));
+            .switchIfEmpty(Mono.error(new MailboxException("Unable to update ACL"))));
     }
 
     public Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
-        return cassandraACLDAO.setACL(cassandraId, mailboxACL)
+        return aclDao().flatMap(dao -> dao.setACL(cassandraId, mailboxACL)
             .flatMap(aclDiff -> userMailboxRightsDAO.update(cassandraId, aclDiff)
             .thenReturn(aclDiff))
-            .switchIfEmpty(Mono.defer(() -> Mono.error(new MailboxException("Unable to update ACL"))));
+            .switchIfEmpty(Mono.defer(() -> Mono.error(new MailboxException("Unable to update ACL")))));
     }
 
     public Mono<Void> delete(CassandraId cassandraId) {
-        return cassandraACLDAO.delete(cassandraId);
+        return aclDao().flatMap(dao -> dao.delete(cassandraId));
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2Migration.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2Migration.java
new file mode 100644
index 0000000..9d6c7df
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2Migration.java
@@ -0,0 +1,115 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.migration;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.apache.james.backends.cassandra.migration.Migration;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV2;
+import org.apache.james.mailbox.cassandra.mail.CassandraMailboxDAO;
+import org.apache.james.task.Task;
+import org.apache.james.task.TaskExecutionDetails;
+import org.apache.james.task.TaskType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import reactor.core.scheduler.Schedulers;
+
+public class AclV2Migration implements Migration {
+    private static final int CONCURRENCY = 20;
+
+    static class AclV2MigrationTask implements Task {
+        private final AclV2Migration migration;
+
+        AclV2MigrationTask(AclV2Migration migration) {
+            this.migration = migration;
+        }
+
+        @Override
+        public Result run() throws InterruptedException {
+            return migration.runTask();
+        }
+
+        @Override
+        public TaskType type() {
+            return TYPE;
+        }
+
+        @Override
+        public Optional<TaskExecutionDetails.AdditionalInformation> details() {
+            return Optional.of(migration.getAdditionalInformation());
+        }
+    }
+
+    public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation {
+        private final Instant timestamp;
+
+        public AdditionalInformation(Instant timestamp) {
+            this.timestamp = timestamp;
+        }
+
+        @Override
+        public Instant timestamp() {
+            return timestamp;
+        }
+    }
+
+    public static final Logger LOGGER = LoggerFactory.getLogger(AclV2Migration.class);
+    public static final TaskType TYPE = TaskType.of("acl-v2-migration");
+
+    private final CassandraMailboxDAO mailboxDAO;
+    private final CassandraACLDAOV1 daoV1;
+    private final CassandraACLDAOV2 daoV2;
+
+    @Inject
+    public AclV2Migration(CassandraMailboxDAO mailboxDAO, CassandraACLDAOV1 daoV1, CassandraACLDAOV2 daoV2) {
+        this.mailboxDAO = mailboxDAO;
+        this.daoV1 = daoV1;
+        this.daoV2 = daoV2;
+    }
+
+    @Override
+    public void apply() {
+        mailboxDAO.retrieveAllMailboxes()
+            .flatMap(mailbox -> {
+                CassandraId id = (CassandraId) mailbox.getMailboxId();
+                return daoV1.getACL(id)
+                    .flatMap(acl -> daoV2.doSetACL(id, acl));
+            }, CONCURRENCY)
+            .doOnError(t -> LOGGER.error("Error while performing migration", t))
+            .subscribeOn(Schedulers.elastic())
+            .blockLast();
+    }
+
+    @Override
+    public Task asTask() {
+        return new AclV2MigrationTask(this);
+    }
+
+    AdditionalInformation getAdditionalInformation() {
+        return new AdditionalInformation(Clock.systemUTC().instant());
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskAdditionalInformationDTO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskAdditionalInformationDTO.java
new file mode 100644
index 0000000..2726dd0
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskAdditionalInformationDTO.java
@@ -0,0 +1,69 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.migration;
+
+import java.time.Instant;
+
+import org.apache.james.json.DTOModule;
+import org.apache.james.server.task.json.dto.AdditionalInformationDTO;
+import org.apache.james.server.task.json.dto.AdditionalInformationDTOModule;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class AclV2MigrationTaskAdditionalInformationDTO implements AdditionalInformationDTO {
+    private static AclV2MigrationTaskAdditionalInformationDTO fromDomainObject(AclV2Migration.AdditionalInformation additionalInformation, String type) {
+        return new AclV2MigrationTaskAdditionalInformationDTO(
+            type,
+            additionalInformation.timestamp()
+        );
+    }
+
+    public static final AdditionalInformationDTOModule<AclV2Migration.AdditionalInformation, AclV2MigrationTaskAdditionalInformationDTO> MODULE =
+        DTOModule
+            .forDomainObject(AclV2Migration.AdditionalInformation.class)
+            .convertToDTO(AclV2MigrationTaskAdditionalInformationDTO.class)
+            .toDomainObjectConverter(AclV2MigrationTaskAdditionalInformationDTO::toDomainObject)
+            .toDTOConverter(AclV2MigrationTaskAdditionalInformationDTO::fromDomainObject)
+            .typeName(AclV2Migration.TYPE.asString())
+            .withFactory(AdditionalInformationDTOModule::new);
+
+    private final String type;
+    private final Instant timestamp;
+
+    public AclV2MigrationTaskAdditionalInformationDTO(@JsonProperty("type") String type,
+                                                      @JsonProperty("timestamp") Instant timestamp) {
+        this.type = type;
+        this.timestamp = timestamp;
+    }
+
+    @Override
+    public Instant getTimestamp() {
+        return timestamp;
+    }
+
+    @Override
+    public String getType() {
+        return type;
+    }
+
+    private AclV2Migration.AdditionalInformation toDomainObject() {
+        return new AclV2Migration.AdditionalInformation(timestamp);
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskDTO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskDTO.java
new file mode 100644
index 0000000..8ce494d
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskDTO.java
@@ -0,0 +1,59 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.migration;
+
+import java.util.function.Function;
+
+import org.apache.james.json.DTOModule;
+import org.apache.james.server.task.json.dto.TaskDTO;
+import org.apache.james.server.task.json.dto.TaskDTOModule;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class AclV2MigrationTaskDTO implements TaskDTO {
+
+    private static AclV2MigrationTaskDTO fromDomainObject(AclV2Migration.AclV2MigrationTask task, String type) {
+        return new AclV2MigrationTaskDTO(type);
+    }
+
+    public static final Function<AclV2Migration, TaskDTOModule<AclV2Migration.AclV2MigrationTask, AclV2MigrationTaskDTO>> MODULE = (migration) ->
+        DTOModule
+            .forDomainObject(AclV2Migration.AclV2MigrationTask.class)
+            .convertToDTO(AclV2MigrationTaskDTO.class)
+            .toDomainObjectConverter(dto -> dto.toDomainObject(migration))
+            .toDTOConverter(AclV2MigrationTaskDTO::fromDomainObject)
+            .typeName(AclV2Migration.TYPE.asString())
+            .withFactory(TaskDTOModule::new);
+
+    private final String type;
+
+    public AclV2MigrationTaskDTO(@JsonProperty("type") String type) {
+        this.type = type;
+    }
+
+    @Override
+    public String getType() {
+        return type;
+    }
+
+    private AclV2Migration.AclV2MigrationTask toDomainObject(AclV2Migration migration) {
+        return new AclV2Migration.AclV2MigrationTask(migration);
+    }
+}
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 cd710d9..f1aa8b2 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
@@ -33,6 +33,8 @@ import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.blob.api.BlobStore;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.cassandra.BlobTables;
@@ -45,6 +47,7 @@ import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
@@ -792,7 +795,9 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
                 rightsDAO(cassandraCluster),
                 new CassandraACLDAOV1(cassandraCluster.getConf(),
                     CassandraConfiguration.DEFAULT_CONFIGURATION,
-                    cassandra.getCassandraConsistenciesConfiguration()));
+                    cassandra.getCassandraConsistenciesConfiguration()),
+                new CassandraACLDAOV2(cassandraCluster.getConf()),
+                new CassandraSchemaVersionManager(new CassandraSchemaVersionDAO(cassandraCluster.getConf())));
         }
 
         private CassandraUserMailboxRightsDAO rightsDAO(CassandraCluster cassandraCluster) {
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperContract.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperContract.java
index 975bafc..e40d87e 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperContract.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperContract.java
@@ -26,23 +26,17 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
 
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.util.concurrent.NamedThreadFactory;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
 abstract class CassandraACLMapperContract {
     static final CassandraId MAILBOX_ID = CassandraId.of(UUID.fromString("464765a0-e4e7-11e4-aba4-710c1de3782b"));
 
-    @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraAclModule.MODULE);
-
     ExecutorService executor;
 
     abstract CassandraACLMapper cassandraACLMapper();
@@ -65,7 +59,7 @@ abstract class CassandraACLMapperContract {
     }
 
     @Test
-    void deleteShouldRemoveACL() throws Exception {
+    void deleteShouldRemoveACL() {
         MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
         MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
index e55e158..7cfa3e5 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
@@ -31,9 +31,14 @@ import java.util.concurrent.TimeoutException;
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.Scenario.Barrier;
+import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
 import org.apache.james.mailbox.model.MailboxACL;
@@ -43,15 +48,22 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 
 class CassandraACLMapperV1Test extends CassandraACLMapperContract {
     @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraAclModule.MODULE);
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
+        CassandraModule.aggregateModules(CassandraAclModule.MODULE, CassandraSchemaVersionModule.MODULE));
 
     private CassandraACLMapper cassandraACLMapper;
 
     @BeforeEach
     void setUp(CassandraCluster cassandra) {
+        CassandraSchemaVersionDAO schemaVersionDAO = new CassandraSchemaVersionDAO(cassandra.getConf());
+        schemaVersionDAO.truncateVersion().block();
+        schemaVersionDAO.updateVersion(new SchemaVersion(9)).block();
+        CassandraSchemaVersionManager versionManager = new CassandraSchemaVersionManager(schemaVersionDAO);
         cassandraACLMapper =  new CassandraACLMapper(
             new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-            new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT));
+            new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT),
+            new CassandraACLDAOV2(cassandra.getConf()),
+            versionManager);
     }
 
     @Override
@@ -97,8 +109,8 @@ class CassandraACLMapperV1Test extends CassandraACLMapperContract {
         MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
         MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
         MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
-        Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights);
-        Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights);
+        Future<Boolean> future1 = performACLUpdateInExecutor(executor, keyBob, rights);
+        Future<Boolean> future2 = performACLUpdateInExecutor(executor, keyAlice, rights);
 
         barrier.awaitCaller();
         barrier.releaseCaller();
@@ -124,8 +136,8 @@ class CassandraACLMapperV1Test extends CassandraACLMapperContract {
 
         MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
         MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
-        Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights);
-        Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights);
+        Future<Boolean> future1 = performACLUpdateInExecutor(executor, keyBob, rights);
+        Future<Boolean> future2 = performACLUpdateInExecutor(executor, keyAlice, rights);
 
         barrier.awaitCaller();
         barrier.releaseCaller();
@@ -143,15 +155,9 @@ class CassandraACLMapperV1Test extends CassandraACLMapperContract {
         }
     }
 
-    private Future<Boolean> performACLUpdateInExecutor(CassandraCluster cassandra, ExecutorService executor, MailboxACL.EntryKey key, MailboxACL.Rfc4314Rights rights) {
+    private Future<Boolean> performACLUpdateInExecutor(ExecutorService executor, MailboxACL.EntryKey key, MailboxACL.Rfc4314Rights rights) {
         return executor.submit(() -> {
-            CassandraACLMapper aclMapper = new CassandraACLMapper(
-                new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-                new CassandraACLDAOV1(cassandra.getConf(),
-                    CassandraConfiguration.DEFAULT_CONFIGURATION,
-                    cassandraCluster.getCassandraConsistenciesConfiguration()));
-
-            aclMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition()).block();
+            cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition()).block();
             return true;
         });
     }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
index 434c367..f6f8cef 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
@@ -30,7 +30,14 @@ import java.util.concurrent.TimeoutException;
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.Scenario.Barrier;
+import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.junit.jupiter.api.BeforeEach;
@@ -39,16 +46,23 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 
 class CassandraACLMapperV2Test extends CassandraACLMapperContract {
     @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraAclModule.MODULE);
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
+        CassandraModule.aggregateModules(CassandraAclModule.MODULE, CassandraSchemaVersionModule.MODULE));
 
     private CassandraACLMapper cassandraACLMapper;
 
     @BeforeEach
     void setUp(CassandraCluster cassandra) {
         cassandra.getConf().printStatements();
-        cassandraACLMapper = new CassandraACLMapper(
+        CassandraSchemaVersionDAO schemaVersionDAO = new CassandraSchemaVersionDAO(cassandra.getConf());
+        schemaVersionDAO.truncateVersion().block();
+        schemaVersionDAO.updateVersion(new SchemaVersion(10)).block();
+        CassandraSchemaVersionManager versionManager = new CassandraSchemaVersionManager(schemaVersionDAO);
+        cassandraACLMapper =  new CassandraACLMapper(
             new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-            new CassandraACLDAOV2(cassandra.getConf()));
+            new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT),
+            new CassandraACLDAOV2(cassandra.getConf()),
+            versionManager);
     }
 
     @Override
@@ -68,8 +82,8 @@ class CassandraACLMapperV2Test extends CassandraACLMapperContract {
         MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
         MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
         MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
-        Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights);
-        Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights);
+        Future<Boolean> future1 = performACLUpdateInExecutor(executor, keyBob, rights);
+        Future<Boolean> future2 = performACLUpdateInExecutor(executor, keyAlice, rights);
 
         barrier.awaitCaller();
         barrier.releaseCaller();
@@ -95,8 +109,8 @@ class CassandraACLMapperV2Test extends CassandraACLMapperContract {
 
         MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
         MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
-        Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights);
-        Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights);
+        Future<Boolean> future1 = performACLUpdateInExecutor(executor, keyBob, rights);
+        Future<Boolean> future2 = performACLUpdateInExecutor(executor, keyAlice, rights);
 
         barrier.awaitCaller();
         barrier.releaseCaller();
@@ -114,13 +128,9 @@ class CassandraACLMapperV2Test extends CassandraACLMapperContract {
         }
     }
 
-    private Future<Boolean> performACLUpdateInExecutor(CassandraCluster cassandra, ExecutorService executor, MailboxACL.EntryKey key, MailboxACL.Rfc4314Rights rights) {
+    private Future<Boolean> performACLUpdateInExecutor(ExecutorService executor, MailboxACL.EntryKey key, MailboxACL.Rfc4314Rights rights) {
         return executor.submit(() -> {
-            CassandraACLMapper aclMapper = new CassandraACLMapper(
-                new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-                new CassandraACLDAOV2(cassandra.getConf()));
-
-            aclMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition()).block();
+            cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition()).block();
             return true;
         });
     }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
index f5c2f6b..678dd69 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
@@ -105,7 +105,9 @@ class CassandraMailboxMapperTest {
             new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
             new CassandraACLDAOV1(cassandra.getConf(),
                 CassandraConfiguration.DEFAULT_CONFIGURATION,
-                cassandraCluster.getCassandraConsistenciesConfiguration()));
+                cassandraCluster.getCassandraConsistenciesConfiguration()),
+            new CassandraACLDAOV2(cassandra.getConf()),
+            new CassandraSchemaVersionManager(new CassandraSchemaVersionDAO(cassandra.getConf())));
         versionDAO = new CassandraSchemaVersionDAO(cassandra.getConf());
 
         versionDAO.truncateVersion()
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskSerializationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskSerializationTest.java
new file mode 100644
index 0000000..711bb3e
--- /dev/null
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTaskSerializationTest.java
@@ -0,0 +1,52 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.migration;
+
+import static org.mockito.Mockito.mock;
+
+import java.time.Instant;
+
+import org.apache.james.JsonSerializationVerifier;
+import org.junit.jupiter.api.Test;
+
+class AclV2MigrationTaskSerializationTest {
+    private static final Instant TIMESTAMP = Instant.parse("2018-11-13T12:00:55Z");
+    private static final AclV2Migration MIGRATION = mock(AclV2Migration.class);
+    private static final AclV2Migration.AclV2MigrationTask TASK = new AclV2Migration.AclV2MigrationTask(MIGRATION);
+    private static final String SERIALIZED_TASK = "{\"type\": \"acl-v2-migration\"}";
+    private static final AclV2Migration.AdditionalInformation DETAILS = new AclV2Migration.AdditionalInformation(TIMESTAMP);
+    private static final String SERIALIZED_ADDITIONAL_INFORMATION = "{\"type\": \"acl-v2-migration\", \"timestamp\":\"2018-11-13T12:00:55Z\"}";
+
+    @Test
+    void taskShouldBeSerializable() throws Exception {
+        JsonSerializationVerifier.dtoModule(AclV2MigrationTaskDTO.MODULE.apply(MIGRATION))
+            .bean(TASK)
+            .json(SERIALIZED_TASK)
+            .verify();
+    }
+
+    @Test
+    void additionalInformationShouldBeSerializable() throws Exception {
+        JsonSerializationVerifier.dtoModule(AclV2MigrationTaskAdditionalInformationDTO.MODULE)
+            .bean(DETAILS)
+            .json(SERIALIZED_ADDITIONAL_INFORMATION)
+            .verify();
+    }
+}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java
new file mode 100644
index 0000000..213df82
--- /dev/null
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java
@@ -0,0 +1,112 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.migration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
+import org.apache.james.core.Username;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV2;
+import org.apache.james.mailbox.cassandra.mail.CassandraMailboxDAO;
+import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
+import org.apache.james.mailbox.cassandra.modules.CassandraMailboxModule;
+import org.apache.james.mailbox.model.Mailbox;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.apache.james.mailbox.model.MailboxConstants;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.UidValidity;
+import org.apache.james.task.Task;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import com.google.common.collect.ImmutableMap;
+
+class AclV2MigrationTest {
+    private static final CassandraId MAILBOX_ID = CassandraId.timeBased();
+    private static final Mailbox MAILBOX = new Mailbox(new MailboxPath(MailboxConstants.USER_NAMESPACE, Username.of("bob"), MailboxConstants.INBOX),
+        UidValidity.generate(), MAILBOX_ID);
+
+    public static final CassandraModule MODULES = CassandraModule.aggregateModules(
+        CassandraMailboxModule.MODULE,
+        CassandraAclModule.MODULE,
+        CassandraSchemaVersionModule.MODULE);
+
+    @RegisterExtension
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULES);
+
+    private CassandraACLDAOV1 daoV1;
+    private CassandraACLDAOV2 daoV2;
+    private CassandraMailboxDAO mailboxDAO;
+    private AclV2Migration migration;
+
+    @BeforeEach
+    void setUp(CassandraCluster cassandra) {
+        mailboxDAO = new CassandraMailboxDAO(cassandra.getConf(), cassandra.getTypesProvider(), CassandraConsistenciesConfiguration.DEFAULT);
+        daoV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
+        daoV2 = new CassandraACLDAOV2(cassandra.getConf());
+        migration = new AclV2Migration(mailboxDAO, daoV1, daoV2);
+    }
+
+    @Test
+    void shouldCompleteWhenNoMailboxes() throws Exception {
+        Task.Result result = migration.runTask();
+
+        assertThat(result).isEqualTo(Task.Result.COMPLETED);
+    }
+
+    @Test
+    void shouldCompleteWhenMailboxWithNoAcl() throws Exception {
+        mailboxDAO.save(MAILBOX).block();
+
+        Task.Result result = migration.runTask();
+
+        assertThat(result).isEqualTo(Task.Result.COMPLETED);
+    }
+
+    @Test
+    void shouldCompleteWhenMailboxWithAcl() throws Exception {
+        mailboxDAO.save(MAILBOX).block();
+        MailboxACL acl = new MailboxACL(ImmutableMap.of(MailboxACL.EntryKey.createUserEntryKey(Username.of("alice")), MailboxACL.FULL_RIGHTS));
+        daoV1.setACL(MAILBOX_ID, acl).block();
+
+        Task.Result result = migration.runTask();
+
+        assertThat(result).isEqualTo(Task.Result.COMPLETED);
+    }
+
+    @Test
+    void shouldCopyAclToNewestVersion() throws Exception {
+        mailboxDAO.save(MAILBOX).block();
+        MailboxACL acl = new MailboxACL(ImmutableMap.of(MailboxACL.EntryKey.createUserEntryKey(Username.of("alice")), MailboxACL.FULL_RIGHTS));
+        daoV1.setACL(MAILBOX_ID, acl).block();
+
+        Task.Result result = migration.runTask();
+
+        assertThat(daoV2.getACL(MAILBOX_ID).block()).isEqualTo(acl);
+    }
+}
\ No newline at end of file
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
index 7ab3f53..0d72d2b 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
@@ -32,6 +32,7 @@ import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraIdAndPath;
 import org.apache.james.mailbox.cassandra.mail.CassandraMailboxDAO;
@@ -104,7 +105,9 @@ class MailboxPathV2MigrationTest {
                 new CassandraACLDAOV1(
                     cassandra.getConf(),
                     CassandraConfiguration.DEFAULT_CONFIGURATION,
-                    cassandraCluster.getCassandraConsistenciesConfiguration())),
+                    cassandraCluster.getCassandraConsistenciesConfiguration()),
+                new CassandraACLDAOV2(cassandra.getConf()),
+                new CassandraSchemaVersionManager(new CassandraSchemaVersionDAO(cassandra.getConf()))),
             new CassandraSchemaVersionManager(new CassandraSchemaVersionDAO(cassandra.getConf())),
             CassandraConfiguration.DEFAULT_CONFIGURATION);
     }
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
index 0afa4fb..5db0098 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
@@ -42,6 +42,7 @@ import org.apache.james.mailbox.cassandra.DeleteMessageListener;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
@@ -123,6 +124,7 @@ public class CassandraMailboxModule extends AbstractModule {
         bind(CassandraMailboxCounterDAO.class).in(Scopes.SINGLETON);
         bind(CassandraMailboxDAO.class).in(Scopes.SINGLETON);
         bind(CassandraACLDAOV1.class).in(Scopes.SINGLETON);
+        bind(CassandraACLDAOV2.class).in(Scopes.SINGLETON);
         bind(CassandraMailboxPathDAOImpl.class).in(Scopes.SINGLETON);
         bind(CassandraMailboxPathV2DAO.class).in(Scopes.SINGLETON);
         bind(CassandraMailboxPathV3DAO.class).in(Scopes.SINGLETON);
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/webadmin/CassandraRoutesModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/webadmin/CassandraRoutesModule.java
index ff0f783..31caeed 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/webadmin/CassandraRoutesModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/webadmin/CassandraRoutesModule.java
@@ -25,6 +25,7 @@ import org.apache.james.backends.cassandra.migration.MigrationTask;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.backends.cassandra.versions.SchemaTransition;
 import org.apache.james.backends.cassandra.versions.SchemaVersion;
+import org.apache.james.mailbox.cassandra.mail.migration.AclV2Migration;
 import org.apache.james.mailbox.cassandra.mail.migration.MailboxPathV2Migration;
 import org.apache.james.mailbox.cassandra.mail.migration.MailboxPathV3Migration;
 import org.apache.james.mailbox.cassandra.mail.migration.MessageV3Migration;
@@ -44,6 +45,7 @@ public class CassandraRoutesModule extends AbstractModule {
     private static final SchemaTransition FROM_V6_TO_V7 = SchemaTransition.to(new SchemaVersion(7));
     private static final SchemaTransition FROM_V7_TO_V8 = SchemaTransition.to(new SchemaVersion(8));
     private static final SchemaTransition FROM_V8_TO_V9 = SchemaTransition.to(new SchemaVersion(9));
+    private static final SchemaTransition FROM_V9_TO_V10 = SchemaTransition.to(new SchemaVersion(10));
 
     @Override
     protected void configure() {
@@ -63,6 +65,7 @@ public class CassandraRoutesModule extends AbstractModule {
         allMigrationClazzBinder.addBinding(FROM_V6_TO_V7).to(MappingsSourcesMigration.class);
         allMigrationClazzBinder.addBinding(FROM_V7_TO_V8).to(MailboxPathV3Migration.class);
         allMigrationClazzBinder.addBinding(FROM_V8_TO_V9).to(MessageV3Migration.class);
+        allMigrationClazzBinder.addBinding(FROM_V9_TO_V10).to(AclV2Migration.class);
 
         bind(SchemaVersion.class)
             .annotatedWith(Names.named(CassandraMigrationService.LATEST_VERSION))


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


[james-project] 03/13: JAMES-3435 CRDT friendly version of CassandraACLDAO

Posted by bt...@apache.org.
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 482319701125f77d2c4377aa6c6386c3f0b998f5
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Dec 2 12:19:04 2020 +0700

    JAMES-3435 CRDT friendly version of CassandraACLDAO
    
    Relies on CRDT for concurrency handling.
---
 .../mailbox/cassandra/mail/CassandraACLDAO.java    | 193 +--------------------
 ...CassandraACLDAO.java => CassandraACLDAOV1.java} |  18 +-
 .../mailbox/cassandra/mail/CassandraACLDAOV2.java  | 188 ++++++++++++++++++++
 .../cassandra/modules/CassandraAclModule.java      |  13 ++
 .../cassandra/table/CassandraACLV2Table.java       |  28 +++
 .../cassandra/CassandraMailboxManagerTest.java     |   4 +-
 .../cassandra/mail/CassandraACLMapperContract.java | 142 +++++++++++++++
 ...pperTest.java => CassandraACLMapperV1Test.java} | 112 +-----------
 .../cassandra/mail/CassandraACLMapperV2Test.java   | 128 ++++++++++++++
 .../cassandra/mail/CassandraMailboxMapperTest.java |   2 +-
 .../mail/migration/MailboxPathV2MigrationTest.java |   4 +-
 .../mailbox/cassandra/mail/utils/GuiceUtils.java   |   3 +
 .../modules/mailbox/CassandraMailboxModule.java    |   4 +-
 13 files changed, 534 insertions(+), 305 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAO.java
index 73e5c0f..627baec 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAO.java
@@ -19,203 +19,24 @@
 
 package org.apache.james.mailbox.cassandra.mail;
 
-import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.set;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.update;
+import java.util.function.Supplier;
 
-import java.io.IOException;
-import java.util.function.Function;
-
-import javax.inject.Inject;
-
-import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
-import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
-import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
 import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.cassandra.json.MailboxACLJsonConverter;
-import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
-import org.apache.james.mailbox.cassandra.table.CassandraMailboxTable;
-import org.apache.james.mailbox.exception.UnsupportedRightException;
 import org.apache.james.mailbox.model.MailboxACL;
-import org.apache.james.util.FunctionalUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.datastax.driver.core.ConsistencyLevel;
-import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.Row;
-import com.datastax.driver.core.Session;
-import com.datastax.driver.core.querybuilder.QueryBuilder;
-import com.fasterxml.jackson.core.JsonProcessingException;
 
 import reactor.core.publisher.Mono;
 
-public class CassandraACLDAO {
-    public static final int INITIAL_VALUE = 0;
-    private static final Logger LOG = LoggerFactory.getLogger(CassandraACLDAO.class);
-    private static final String OLD_VERSION = "oldVersion";
-
-    private final CassandraAsyncExecutor executor;
-    private final int maxAclRetry;
-    private final PreparedStatement conditionalInsertStatement;
-    private final PreparedStatement conditionalUpdateStatement;
-    private final PreparedStatement readStatement;
-    private final PreparedStatement deleteStatement;
-    private final ConsistencyLevel consistencyLevel;
-
-    @Inject
-    public CassandraACLDAO(Session session,
-                           CassandraConfiguration cassandraConfiguration,
-                           CassandraConsistenciesConfiguration consistenciesConfiguration) {
-        this.executor = new CassandraAsyncExecutor(session);
-        this.maxAclRetry = cassandraConfiguration.getAclMaxRetry();
-        this.consistencyLevel = consistenciesConfiguration.getLightweightTransaction();
-        this.conditionalInsertStatement = prepareConditionalInsert(session);
-        this.conditionalUpdateStatement = prepareConditionalUpdate(session);
-        this.readStatement = prepareReadStatement(session);
-        this.deleteStatement = prepareDelete(session);
-    }
-
-    private PreparedStatement prepareDelete(Session session) {
-        return session.prepare(
-            QueryBuilder.delete().from(CassandraACLTable.TABLE_NAME)
-                .where(eq(CassandraACLTable.ID, bindMarker(CassandraACLTable.ID)))
-                .ifExists());
-    }
-
-    private PreparedStatement prepareConditionalInsert(Session session) {
-        return session.prepare(
-            insertInto(CassandraACLTable.TABLE_NAME)
-                .value(CassandraACLTable.ID, bindMarker(CassandraACLTable.ID))
-                .value(CassandraACLTable.ACL, bindMarker(CassandraACLTable.ACL))
-                .value(CassandraACLTable.VERSION, INITIAL_VALUE)
-                .ifNotExists());
-    }
-
-    private PreparedStatement prepareConditionalUpdate(Session session) {
-        return session.prepare(
-            update(CassandraACLTable.TABLE_NAME)
-                .where(eq(CassandraACLTable.ID, bindMarker(CassandraACLTable.ID)))
-                .with(set(CassandraACLTable.ACL, bindMarker(CassandraACLTable.ACL)))
-                .and(set(CassandraACLTable.VERSION, bindMarker(CassandraACLTable.VERSION)))
-                .onlyIf(eq(CassandraACLTable.VERSION, bindMarker(OLD_VERSION))));
-    }
-
-    private PreparedStatement prepareReadStatement(Session session) {
-        return session.prepare(
-            select(CassandraACLTable.ACL, CassandraACLTable.VERSION)
-                .from(CassandraACLTable.TABLE_NAME)
-                .where(eq(CassandraMailboxTable.ID, bindMarker(CassandraACLTable.ID))));
-    }
-
-    Mono<MailboxACL> getACL(CassandraId cassandraId) {
-        return getStoredACLRow(cassandraId)
-            .map(row -> getAcl(cassandraId, row));
-    }
-
-    private MailboxACL getAcl(CassandraId cassandraId, Row row) {
-        String serializedACL = row.getString(CassandraACLTable.ACL);
-        return deserializeACL(cassandraId, serializedACL);
-    }
-
-    public Mono<ACLDiff> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
-        return Mono.fromCallable(() -> MailboxACL.EMPTY.apply(command))
-            .flatMap(replacement -> doUpdateAcl(cassandraId, aclWithVersion -> aclWithVersion.apply(command), replacement));
-    }
-
-    public Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
-        return doUpdateAcl(cassandraId, acl -> new ACLWithVersion(acl.version, mailboxACL), mailboxACL);
-    }
-
-    Mono<ACLDiff> doUpdateAcl(CassandraId cassandraId, Function<ACLWithVersion, ACLWithVersion> aclTransformation, MailboxACL replacement) {
-        return getAclWithVersion(cassandraId)
-            .flatMap(aclWithVersion ->
-                    updateStoredACL(cassandraId, aclTransformation.apply(aclWithVersion))
-                            .map(newACL -> ACLDiff.computeDiff(aclWithVersion.mailboxACL, newACL)))
-            .switchIfEmpty(insertACL(cassandraId, replacement)
-                    .map(newACL -> ACLDiff.computeDiff(MailboxACL.EMPTY, newACL)))
-            .single()
-            .retry(maxAclRetry);
-    }
-
-    private Mono<Row> getStoredACLRow(CassandraId cassandraId) {
-        return executor.executeSingleRow(
-            readStatement.bind()
-                .setUUID(CassandraACLTable.ID, cassandraId.asUuid())
-                .setConsistencyLevel(consistencyLevel));
-    }
-
-    private Mono<MailboxACL> updateStoredACL(CassandraId cassandraId, ACLWithVersion aclWithVersion) {
-        return executor.executeReturnApplied(
-            conditionalUpdateStatement.bind()
-                .setUUID(CassandraACLTable.ID, cassandraId.asUuid())
-                .setString(CassandraACLTable.ACL, convertAclToJson(aclWithVersion.mailboxACL))
-                .setLong(CassandraACLTable.VERSION, aclWithVersion.version + 1)
-                .setLong(OLD_VERSION, aclWithVersion.version))
-            .filter(FunctionalUtils.identityPredicate())
-            .map(any -> aclWithVersion.mailboxACL);
-    }
+public interface CassandraACLDAO {
+    interface CassandraACLDAOSupplier extends Supplier<CassandraACLDAO> {
 
-    public Mono<Void> delete(CassandraId cassandraId) {
-        return executor.executeVoid(
-            deleteStatement.bind()
-                .setUUID(CassandraACLTable.ID, cassandraId.asUuid()));
     }
 
-    private Mono<MailboxACL> insertACL(CassandraId cassandraId, MailboxACL acl) {
-        return executor.executeReturnApplied(
-            conditionalInsertStatement.bind()
-                    .setUUID(CassandraACLTable.ID, cassandraId.asUuid())
-                    .setString(CassandraACLTable.ACL, convertAclToJson(acl)))
-            .filter(FunctionalUtils.identityPredicate())
-            .map(any -> acl);
-    }
+    Mono<Void> delete(CassandraId cassandraId);
 
-    private String convertAclToJson(MailboxACL acl) {
-        try {
-            return MailboxACLJsonConverter.toJson(acl);
-        } catch (JsonProcessingException exception) {
-            throw new RuntimeException(exception);
-        }
-    }
+    Mono<MailboxACL> getACL(CassandraId cassandraId);
 
-    private Mono<ACLWithVersion> getAclWithVersion(CassandraId cassandraId) {
-        return getStoredACLRow(cassandraId)
-            .map(acl -> new ACLWithVersion(acl.getLong(CassandraACLTable.VERSION),
-                deserializeACL(cassandraId, acl.getString(CassandraACLTable.ACL))));
-    }
+    Mono<ACLDiff> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command);
 
-    private MailboxACL deserializeACL(CassandraId cassandraId, String serializedACL) {
-        try {
-            return MailboxACLJsonConverter.toACL(serializedACL);
-        } catch (IOException exception) {
-            LOG.error("Unable to read stored ACL. " +
-                "We will use empty ACL instead." +
-                "Mailbox is {} ." +
-                "ACL is {}", cassandraId, serializedACL, exception);
-            return MailboxACL.EMPTY;
-        }
-    }
-
-    private static class ACLWithVersion {
-        private final long version;
-        private final MailboxACL mailboxACL;
-
-        public ACLWithVersion(long version, MailboxACL mailboxACL) {
-            this.version = version;
-            this.mailboxACL = mailboxACL;
-        }
-
-        public ACLWithVersion apply(MailboxACL.ACLCommand command) {
-            try {
-                return new ACLWithVersion(version, mailboxACL.apply(command));
-            } catch (UnsupportedRightException exception) {
-                throw new RuntimeException(exception);
-            }
-        }
-    }
+    Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL);
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV1.java
similarity index 94%
copy from mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAO.java
copy to mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV1.java
index 73e5c0f..3bd9c47 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV1.java
@@ -54,9 +54,9 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 
 import reactor.core.publisher.Mono;
 
-public class CassandraACLDAO {
+public class CassandraACLDAOV1 implements CassandraACLDAO {
     public static final int INITIAL_VALUE = 0;
-    private static final Logger LOG = LoggerFactory.getLogger(CassandraACLDAO.class);
+    private static final Logger LOG = LoggerFactory.getLogger(CassandraACLDAOV1.class);
     private static final String OLD_VERSION = "oldVersion";
 
     private final CassandraAsyncExecutor executor;
@@ -68,9 +68,9 @@ public class CassandraACLDAO {
     private final ConsistencyLevel consistencyLevel;
 
     @Inject
-    public CassandraACLDAO(Session session,
-                           CassandraConfiguration cassandraConfiguration,
-                           CassandraConsistenciesConfiguration consistenciesConfiguration) {
+    public CassandraACLDAOV1(Session session,
+                             CassandraConfiguration cassandraConfiguration,
+                             CassandraConsistenciesConfiguration consistenciesConfiguration) {
         this.executor = new CassandraAsyncExecutor(session);
         this.maxAclRetry = cassandraConfiguration.getAclMaxRetry();
         this.consistencyLevel = consistenciesConfiguration.getLightweightTransaction();
@@ -112,7 +112,7 @@ public class CassandraACLDAO {
                 .where(eq(CassandraMailboxTable.ID, bindMarker(CassandraACLTable.ID))));
     }
 
-    Mono<MailboxACL> getACL(CassandraId cassandraId) {
+    public Mono<MailboxACL> getACL(CassandraId cassandraId) {
         return getStoredACLRow(cassandraId)
             .map(row -> getAcl(cassandraId, row));
     }
@@ -134,10 +134,10 @@ public class CassandraACLDAO {
     Mono<ACLDiff> doUpdateAcl(CassandraId cassandraId, Function<ACLWithVersion, ACLWithVersion> aclTransformation, MailboxACL replacement) {
         return getAclWithVersion(cassandraId)
             .flatMap(aclWithVersion ->
-                    updateStoredACL(cassandraId, aclTransformation.apply(aclWithVersion))
-                            .map(newACL -> ACLDiff.computeDiff(aclWithVersion.mailboxACL, newACL)))
+                updateStoredACL(cassandraId, aclTransformation.apply(aclWithVersion))
+                    .map(newACL -> ACLDiff.computeDiff(aclWithVersion.mailboxACL, newACL)))
             .switchIfEmpty(insertACL(cassandraId, replacement)
-                    .map(newACL -> ACLDiff.computeDiff(MailboxACL.EMPTY, newACL)))
+                .map(newACL -> ACLDiff.computeDiff(MailboxACL.EMPTY, newACL)))
             .single()
             .retry(maxAclRetry);
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
new file mode 100644
index 0000000..9bc2ad3
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
@@ -0,0 +1,188 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.addAll;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.removeAll;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.set;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.update;
+
+import javax.inject.Inject;
+
+import org.apache.commons.lang3.NotImplementedException;
+import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
+import org.apache.james.mailbox.acl.ACLDiff;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
+import org.apache.james.mailbox.cassandra.table.CassandraACLV2Table;
+import org.apache.james.mailbox.model.MailboxACL;
+
+import com.datastax.driver.core.BatchStatement;
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
+import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class CassandraACLDAOV2 implements CassandraACLDAO {
+    private final CassandraAsyncExecutor executor;
+    private final PreparedStatement insertRights;
+    private final PreparedStatement removeRights;
+    private final PreparedStatement replaceRights;
+    private final PreparedStatement delete;
+    private final PreparedStatement read;
+
+    @Inject
+    public CassandraACLDAOV2(Session session) {
+        this.executor = new CassandraAsyncExecutor(session);
+        this.insertRights = prepareInsertRights(session);
+        this.removeRights = prepareRemoveRights(session);
+        this.replaceRights = prepareReplaceRights(session);
+        this.read = prepareRead(session);
+        this.delete = prepareDelete(session);
+    }
+
+    private PreparedStatement prepareDelete(Session session) {
+        return session.prepare(
+            QueryBuilder.delete().from(CassandraACLV2Table.TABLE_NAME)
+                .where(eq(CassandraACLV2Table.ID, bindMarker(CassandraACLV2Table.ID))));
+    }
+
+    private PreparedStatement prepareInsertRights(Session session) {
+        return session.prepare(
+            update(CassandraACLV2Table.TABLE_NAME)
+                .with(addAll(CassandraACLV2Table.RIGHTS, bindMarker(CassandraACLV2Table.RIGHTS)))
+                .where(eq(CassandraACLV2Table.ID, bindMarker(CassandraACLV2Table.ID)))
+                .and(eq(CassandraACLV2Table.KEY, bindMarker(CassandraACLV2Table.KEY))));
+    }
+
+    private PreparedStatement prepareReplaceRights(Session session) {
+        return session.prepare(
+            update(CassandraACLV2Table.TABLE_NAME)
+                .with(set(CassandraACLV2Table.RIGHTS, bindMarker(CassandraACLV2Table.RIGHTS)))
+                .where(eq(CassandraACLV2Table.ID, bindMarker(CassandraACLV2Table.ID)))
+                .and(eq(CassandraACLV2Table.KEY, bindMarker(CassandraACLV2Table.KEY))));
+    }
+
+    private PreparedStatement prepareRemoveRights(Session session) {
+        return session.prepare(
+            update(CassandraACLV2Table.TABLE_NAME)
+                .with(removeAll(CassandraACLV2Table.RIGHTS, bindMarker(CassandraACLV2Table.RIGHTS)))
+                .where(eq(CassandraACLV2Table.ID, bindMarker(CassandraACLV2Table.ID)))
+                .and(eq(CassandraACLV2Table.KEY, bindMarker(CassandraACLV2Table.KEY))));
+    }
+
+    private PreparedStatement prepareRead(Session session) {
+        return session.prepare(
+            select()
+                .from(CassandraACLV2Table.TABLE_NAME)
+                .where(eq(CassandraACLV2Table.ID, bindMarker(CassandraACLV2Table.ID))));
+    }
+
+    public Mono<Void> delete(CassandraId cassandraId) {
+        return executor.executeVoid(
+            delete.bind()
+                .setUUID(CassandraACLTable.ID, cassandraId.asUuid()));
+    }
+
+    public Mono<MailboxACL> getACL(CassandraId cassandraId) {
+        return executor.executeRows(
+            read.bind()
+                .setUUID(CassandraACLTable.ID, cassandraId.asUuid()))
+            .map(Throwing.function(row -> {
+                MailboxACL.EntryKey entryKey = MailboxACL.EntryKey.deserialize(row.getString(CassandraACLV2Table.KEY));
+                MailboxACL.Rfc4314Rights rights = row.getSet(CassandraACLV2Table.RIGHTS, String.class)
+                    .stream()
+                    .map(Throwing.function(MailboxACL.Rfc4314Rights::deserialize))
+                    .reduce(MailboxACL.NO_RIGHTS, Throwing.binaryOperator(MailboxACL.Rfc4314Rights::union));
+                return new MailboxACL(ImmutableMap.of(entryKey, rights));
+            }))
+            .reduce(Throwing.biFunction(MailboxACL::union));
+    }
+
+    public Mono<ACLDiff> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
+        return getACL(cassandraId)
+            .switchIfEmpty(Mono.just(new MailboxACL()))
+            .flatMap(before -> doUpdateACL(cassandraId, command)
+                .then(getACL(cassandraId)
+                    .switchIfEmpty(Mono.just(new MailboxACL()))
+                    .map(after -> ACLDiff.computeDiff(before, after))));
+    }
+
+    public Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
+        return getACL(cassandraId)
+            .flatMap(oldACL -> delete(cassandraId)
+                .then(Flux.fromIterable(mailboxACL.getEntries().entrySet())
+                    .concatMap(entry -> doSetACL(cassandraId, mailboxACL))
+                    .then())
+                .thenReturn(ACLDiff.computeDiff(oldACL, mailboxACL)));
+    }
+
+    private Mono<Void> doUpdateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
+        ImmutableSet<String> rightStrings = asStringSet(command.getRights());
+        switch (command.getEditMode()) {
+            case ADD:
+                return executor.executeVoid(insertRights.bind()
+                    .setUUID(CassandraACLV2Table.ID, cassandraId.asUuid())
+                    .setString(CassandraACLV2Table.KEY, command.getEntryKey().serialize())
+                    .setSet(CassandraACLV2Table.RIGHTS, ImmutableSet.copyOf(rightStrings), String.class));
+            case REMOVE:
+                return executor.executeVoid(removeRights.bind()
+                    .setUUID(CassandraACLV2Table.ID, cassandraId.asUuid())
+                    .setString(CassandraACLV2Table.KEY, command.getEntryKey().serialize())
+                    .setSet(CassandraACLV2Table.RIGHTS, ImmutableSet.copyOf(rightStrings), String.class));
+            case REPLACE:
+                return executor.executeVoid(replaceRights.bind()
+                    .setUUID(CassandraACLV2Table.ID, cassandraId.asUuid())
+                    .setString(CassandraACLV2Table.KEY, command.getEntryKey().serialize())
+                    .setSet(CassandraACLV2Table.RIGHTS, rightStrings, String.class));
+            default:
+                throw new NotImplementedException(command.getEditMode() + "is not supported");
+        }
+    }
+
+    private ImmutableSet<String> asStringSet(MailboxACL.Rfc4314Rights rights) {
+        return rights.list()
+            .stream()
+            .map(MailboxACL.Right::asCharacter)
+            .map(String::valueOf)
+            .collect(Guavate.toImmutableSet());
+    }
+
+    private Mono<Void> doSetACL(CassandraId cassandraId, MailboxACL mailboxACL) {
+        BatchStatement batchStatement = new BatchStatement();
+        mailboxACL.getEntries().entrySet()
+            .stream().map(entry -> replaceRights.bind()
+            .setUUID(CassandraACLV2Table.ID, cassandraId.asUuid())
+            .setString(CassandraACLV2Table.KEY, entry.getKey().serialize())
+            .setSet(CassandraACLV2Table.RIGHTS, asStringSet(entry.getValue()), String.class))
+            .forEach(batchStatement::add);
+
+        return executor.executeVoid(batchStatement);
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraAclModule.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraAclModule.java
index abdecab..8f05801 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraAclModule.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraAclModule.java
@@ -20,12 +20,14 @@
 package org.apache.james.mailbox.cassandra.modules;
 
 import static com.datastax.driver.core.DataType.bigint;
+import static com.datastax.driver.core.DataType.set;
 import static com.datastax.driver.core.DataType.text;
 import static com.datastax.driver.core.DataType.timeuuid;
 
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.utils.CassandraConstants;
 import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
+import org.apache.james.mailbox.cassandra.table.CassandraACLV2Table;
 import org.apache.james.mailbox.cassandra.table.CassandraUserMailboxRightsTable;
 
 import com.datastax.driver.core.schemabuilder.SchemaBuilder;
@@ -42,6 +44,17 @@ public interface CassandraAclModule {
             .addPartitionKey(CassandraACLTable.ID, timeuuid())
             .addColumn(CassandraACLTable.ACL, text())
             .addColumn(CassandraACLTable.VERSION, bigint()))
+
+        .table(CassandraACLV2Table.TABLE_NAME)
+        .comment("Holds mailbox ACLs. This table do not rely on a JSON representation nor on LWT, contrary to the acl table it replaces.")
+        .options(options -> options
+            .caching(SchemaBuilder.KeyCaching.ALL,
+                SchemaBuilder.rows(CassandraConstants.DEFAULT_CACHED_ROW_PER_PARTITION)))
+        .statement(statement -> statement
+            .addPartitionKey(CassandraACLV2Table.ID, timeuuid())
+            .addClusteringColumn(CassandraACLV2Table.KEY, text())
+            .addColumn(CassandraACLV2Table.RIGHTS, set(text())))
+
         .table(CassandraUserMailboxRightsTable.TABLE_NAME)
         .comment("Denormalisation table. Allow to retrieve non personal mailboxIds a user has right on")
         .options(options -> options
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraACLV2Table.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraACLV2Table.java
new file mode 100644
index 0000000..94d1ea1
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraACLV2Table.java
@@ -0,0 +1,28 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.table;
+
+public interface CassandraACLV2Table {
+    String TABLE_NAME = "aclv2";
+
+    String ID = "id";
+    String KEY = "key";
+    String RIGHTS = "rights";
+}
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 919f9a7..cd710d9 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
@@ -44,7 +44,7 @@ import org.apache.james.mailbox.MessageManager.AppendResult;
 import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
-import org.apache.james.mailbox.cassandra.mail.CassandraACLDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
@@ -790,7 +790,7 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
         private CassandraACLMapper aclMapper(CassandraCluster cassandraCluster) {
             return new CassandraACLMapper(
                 rightsDAO(cassandraCluster),
-                new CassandraACLDAO(cassandraCluster.getConf(),
+                new CassandraACLDAOV1(cassandraCluster.getConf(),
                     CassandraConfiguration.DEFAULT_CONFIGURATION,
                     cassandra.getCassandraConsistenciesConfiguration()));
         }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperContract.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperContract.java
new file mode 100644
index 0000000..975bafc
--- /dev/null
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperContract.java
@@ -0,0 +1,142 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.mailbox.cassandra.mail;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.apache.james.util.concurrent.NamedThreadFactory;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+abstract class CassandraACLMapperContract {
+    static final CassandraId MAILBOX_ID = CassandraId.of(UUID.fromString("464765a0-e4e7-11e4-aba4-710c1de3782b"));
+
+    @RegisterExtension
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraAclModule.MODULE);
+
+    ExecutorService executor;
+
+    abstract CassandraACLMapper cassandraACLMapper();
+
+    @BeforeEach
+    void setUpExecutor() {
+        ThreadFactory threadFactory = NamedThreadFactory.withClassName(getClass());
+        executor = Executors.newFixedThreadPool(2, threadFactory);
+    }
+
+
+    @AfterEach
+    void tearDownExecutor() {
+        executor.shutdownNow();
+    }
+
+    @Test
+    void retrieveACLWhenNoACLStoredShouldReturnEmptyACL() {
+        assertThat(cassandraACLMapper().getACL(MAILBOX_ID).blockOptional()).isEmpty();
+    }
+
+    @Test
+    void deleteShouldRemoveACL() throws Exception {
+        MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
+        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
+
+        cassandraACLMapper().updateACL(MAILBOX_ID,
+            MailboxACL.command().key(key).rights(rights).asAddition());
+
+        cassandraACLMapper().delete(MAILBOX_ID).block();
+
+        assertThat(cassandraACLMapper().getACL(MAILBOX_ID).blockOptional()).isEmpty();
+    }
+
+    @Test
+    void deleteShouldNotThrowWhenDoesNotExist() {
+        assertThatCode(() -> cassandraACLMapper().delete(MAILBOX_ID).block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void addACLWhenNoneStoredShouldReturnUpdatedACL() throws Exception {
+        MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
+        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
+
+        cassandraACLMapper().updateACL(MAILBOX_ID,
+            MailboxACL.command().key(key).rights(rights).asAddition()).block();
+
+        assertThat(cassandraACLMapper().getACL(MAILBOX_ID).block())
+            .isEqualTo(new MailboxACL().union(key, rights));
+    }
+
+    @Test
+    void modifyACLWhenStoredShouldReturnUpdatedACL() throws MailboxException {
+        MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
+        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
+
+        cassandraACLMapper().updateACL(MAILBOX_ID, MailboxACL.command().key(keyBob).rights(rights).asAddition()).block();
+        MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
+        cassandraACLMapper().updateACL(MAILBOX_ID, MailboxACL.command().key(keyAlice).rights(rights).asAddition()).block();
+
+        assertThat(cassandraACLMapper().getACL(MAILBOX_ID).block())
+            .isEqualTo(new MailboxACL().union(keyBob, rights).union(keyAlice, rights));
+    }
+
+    @Test
+    void removeWhenStoredShouldReturnUpdatedACL() throws MailboxException {
+        MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
+        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
+
+        cassandraACLMapper().updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition()).block();
+        cassandraACLMapper().updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asRemoval()).block();
+
+        assertThat(cassandraACLMapper().getACL(MAILBOX_ID).blockOptional().orElse(MailboxACL.EMPTY)).isEqualTo(MailboxACL.EMPTY);
+    }
+
+    @Test
+    void replaceForSingleKeyWithNullRightsWhenSingleKeyStoredShouldReturnEmptyACL() throws MailboxException {
+        MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
+        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
+
+        cassandraACLMapper().updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition()).block();
+        cassandraACLMapper().updateACL(MAILBOX_ID, MailboxACL.command().key(key).noRights().asReplacement()).block();
+
+        assertThat(cassandraACLMapper().getACL(MAILBOX_ID).blockOptional().orElse(MailboxACL.EMPTY)).isEqualTo(MailboxACL.EMPTY);
+    }
+
+    @Test
+    void replaceWhenNotStoredShouldUpdateACLEntry() throws MailboxException {
+        MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
+        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
+
+        cassandraACLMapper().updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asReplacement()).block();
+
+        assertThat(cassandraACLMapper().getACL(MAILBOX_ID).block()).isEqualTo(new MailboxACL().union(key, rights));
+    }
+}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
similarity index 59%
rename from mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java
rename to mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
index 0dfd6bc..e55e158 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
@@ -21,14 +21,10 @@ package org.apache.james.mailbox.cassandra.mail;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
 import static org.apache.james.backends.cassandra.Scenario.Builder.awaitOn;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
 
-import java.util.UUID;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
-import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
@@ -36,40 +32,31 @@ import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.Scenario.Barrier;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
-import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.cassandra.mail.utils.GuiceUtils;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
-import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MailboxACL;
-import org.apache.james.util.concurrent.NamedThreadFactory;
-import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-class CassandraACLMapperTest {
-
-    private static final CassandraId MAILBOX_ID = CassandraId.of(UUID.fromString("464765a0-e4e7-11e4-aba4-710c1de3782b"));
-
+class CassandraACLMapperV1Test extends CassandraACLMapperContract {
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraAclModule.MODULE);
 
     private CassandraACLMapper cassandraACLMapper;
-    private ExecutorService executor;
 
     @BeforeEach
     void setUp(CassandraCluster cassandra) {
-        cassandraACLMapper = GuiceUtils.testInjector(cassandra)
-            .getInstance(CassandraACLMapper.class);
-        ThreadFactory threadFactory = NamedThreadFactory.withClassName(getClass());
-        executor = Executors.newFixedThreadPool(2, threadFactory);
+        cassandraACLMapper =  new CassandraACLMapper(
+            new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
+            new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT));
     }
 
-    @AfterEach
-    void tearDown() {
-        executor.shutdownNow();
+    @Override
+    CassandraACLMapper cassandraACLMapper() {
+        return cassandraACLMapper;
     }
 
     @Test
@@ -84,87 +71,6 @@ class CassandraACLMapperTest {
     }
 
     @Test
-    void retrieveACLWhenNoACLStoredShouldReturnEmptyACL() {
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).blockOptional()).isEmpty();
-    }
-
-    @Test
-    void deleteShouldRemoveACL() throws Exception {
-        MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
-        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
-
-        cassandraACLMapper.updateACL(MAILBOX_ID,
-            MailboxACL.command().key(key).rights(rights).asAddition());
-
-        cassandraACLMapper.delete(MAILBOX_ID).block();
-
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).blockOptional()).isEmpty();
-    }
-
-    @Test
-    void deleteShouldNotThrowWhenDoesNotExist() {
-        assertThatCode(() -> cassandraACLMapper.delete(MAILBOX_ID).block())
-            .doesNotThrowAnyException();
-    }
-
-    @Test
-    void addACLWhenNoneStoredShouldReturnUpdatedACL() throws Exception {
-        MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
-        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
-
-        cassandraACLMapper.updateACL(MAILBOX_ID,
-            MailboxACL.command().key(key).rights(rights).asAddition()).block();
-
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block())
-            .isEqualTo(new MailboxACL().union(key, rights));
-    }
-
-    @Test
-    void modifyACLWhenStoredShouldReturnUpdatedACL() throws MailboxException {
-        MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
-        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
-
-        cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(keyBob).rights(rights).asAddition()).block();
-        MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
-        cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(keyAlice).rights(rights).asAddition()).block();
-
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block())
-            .isEqualTo(new MailboxACL().union(keyBob, rights).union(keyAlice, rights));
-    }
-
-    @Test
-    void removeWhenStoredShouldReturnUpdatedACL() throws MailboxException {
-        MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
-        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
-
-        cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition()).block();
-        cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asRemoval()).block();
-
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(MailboxACL.EMPTY);
-    }
-
-    @Test
-    void replaceForSingleKeyWithNullRightsWhenSingleKeyStoredShouldReturnEmptyACL() throws MailboxException {
-        MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
-        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
-
-        cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition()).block();
-        cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).noRights().asReplacement()).block();
-
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(MailboxACL.EMPTY);
-    }
-
-    @Test
-    void replaceWhenNotStoredShouldUpdateACLEntry() throws MailboxException {
-        MailboxACL.EntryKey key = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
-        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
-
-        cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asReplacement()).block();
-
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(new MailboxACL().union(key, rights));
-    }
-
-    @Test
     void updateInvalidACLShouldBeBasedOnEmptyACL(CassandraCluster cassandra) throws Exception {
         cassandra.getConf().execute(
             insertInto(CassandraACLTable.TABLE_NAME)
@@ -241,7 +147,7 @@ class CassandraACLMapperTest {
         return executor.submit(() -> {
             CassandraACLMapper aclMapper = new CassandraACLMapper(
                 new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-                new CassandraACLDAO(cassandra.getConf(),
+                new CassandraACLDAOV1(cassandra.getConf(),
                     CassandraConfiguration.DEFAULT_CONFIGURATION,
                     cassandraCluster.getCassandraConsistenciesConfiguration()));
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
new file mode 100644
index 0000000..434c367
--- /dev/null
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
@@ -0,0 +1,128 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.mailbox.cassandra.mail;
+
+import static org.apache.james.backends.cassandra.Scenario.Builder.awaitOn;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.backends.cassandra.Scenario.Barrier;
+import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+class CassandraACLMapperV2Test extends CassandraACLMapperContract {
+    @RegisterExtension
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraAclModule.MODULE);
+
+    private CassandraACLMapper cassandraACLMapper;
+
+    @BeforeEach
+    void setUp(CassandraCluster cassandra) {
+        cassandra.getConf().printStatements();
+        cassandraACLMapper = new CassandraACLMapper(
+            new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
+            new CassandraACLDAOV2(cassandra.getConf()));
+    }
+
+    @Override
+    CassandraACLMapper cassandraACLMapper() {
+        return cassandraACLMapper;
+    }
+
+    @Test
+    void twoConcurrentUpdatesWhenNoACLStoredShouldReturnACLWithTwoEntries(CassandraCluster cassandra) throws Exception {
+        Barrier barrier = new Barrier(2);
+        cassandra.getConf()
+            .registerScenario(awaitOn(barrier)
+                .thenExecuteNormally()
+                .times(2)
+                .whenQueryStartsWith("SELECT * FROM aclv2 WHERE id=:id;"));
+
+        MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
+        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
+        MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
+        Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights);
+        Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights);
+
+        barrier.awaitCaller();
+        barrier.releaseCaller();
+
+        awaitAll(future1, future2);
+
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block())
+            .isEqualTo(new MailboxACL().union(keyBob, rights).union(keyAlice, rights));
+    }
+
+    @Test
+    void twoConcurrentUpdatesWhenStoredShouldReturnACLWithTwoEntries(CassandraCluster cassandra) throws Exception {
+        MailboxACL.EntryKey keyBenwa = new MailboxACL.EntryKey("benwa", MailboxACL.NameType.user, false);
+        MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
+        cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(keyBenwa).rights(rights).asAddition()).block();
+
+        Barrier barrier = new Barrier(2);
+        cassandra.getConf()
+            .registerScenario(awaitOn(barrier)
+                .thenExecuteNormally()
+                .times(2)
+                .whenQueryStartsWith("SELECT * FROM aclv2 WHERE id=:id;"));
+
+        MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
+        MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
+        Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights);
+        Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights);
+
+        barrier.awaitCaller();
+        barrier.releaseCaller();
+
+        awaitAll(future1, future2);
+
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block())
+            .isEqualTo(new MailboxACL().union(keyBob, rights).union(keyAlice, rights).union(keyBenwa, rights));
+    }
+
+    private void awaitAll(Future<?>... futures) 
+            throws InterruptedException, ExecutionException, TimeoutException {
+        for (Future<?> future : futures) {
+            future.get(10L, TimeUnit.SECONDS);
+        }
+    }
+
+    private Future<Boolean> performACLUpdateInExecutor(CassandraCluster cassandra, ExecutorService executor, MailboxACL.EntryKey key, MailboxACL.Rfc4314Rights rights) {
+        return executor.submit(() -> {
+            CassandraACLMapper aclMapper = new CassandraACLMapper(
+                new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
+                new CassandraACLDAOV2(cassandra.getConf()));
+
+            aclMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition()).block();
+            return true;
+        });
+    }
+
+}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
index 5df1a7b..f5c2f6b 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
@@ -103,7 +103,7 @@ class CassandraMailboxMapperTest {
         CassandraUserMailboxRightsDAO userMailboxRightsDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
         CassandraACLMapper aclMapper = new CassandraACLMapper(
             new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-            new CassandraACLDAO(cassandra.getConf(),
+            new CassandraACLDAOV1(cassandra.getConf(),
                 CassandraConfiguration.DEFAULT_CONFIGURATION,
                 cassandraCluster.getCassandraConsistenciesConfiguration()));
         versionDAO = new CassandraSchemaVersionDAO(cassandra.getConf());
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
index 9979833..7ab3f53 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
@@ -31,7 +31,7 @@ import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManage
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.cassandra.mail.CassandraACLDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraIdAndPath;
 import org.apache.james.mailbox.cassandra.mail.CassandraMailboxDAO;
@@ -101,7 +101,7 @@ class MailboxPathV2MigrationTest {
             userMailboxRightsDAO,
             new CassandraACLMapper(
                 userMailboxRightsDAO,
-                new CassandraACLDAO(
+                new CassandraACLDAOV1(
                     cassandra.getConf(),
                     CassandraConfiguration.DEFAULT_CONFIGURATION,
                     cassandraCluster.getCassandraConsistenciesConfiguration())),
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
index a6d8883..6dc6dab 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
@@ -28,6 +28,8 @@ import org.apache.james.blob.api.BlobStore;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.cassandra.CassandraBlobStoreFactory;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
 import org.apache.james.mailbox.model.MessageId;
 
 import com.datastax.driver.core.Session;
@@ -57,6 +59,7 @@ public class GuiceUtils {
                                         CassandraMessageId.Factory messageIdFactory,
                                         CassandraConfiguration configuration) {
         return Modules.combine(
+            binder -> binder.bind(CassandraACLDAO.class).to(CassandraACLDAOV1.class),
             binder -> binder.bind(MessageId.Factory.class).toInstance(messageIdFactory),
             binder -> binder.bind(BlobId.Factory.class).toInstance(new HashBlobId.Factory()),
             binder -> binder.bind(BlobStore.class).toProvider(() -> CassandraBlobStoreFactory.forTesting(session).passthrough()),
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
index 9427145..0afa4fb 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
@@ -41,7 +41,7 @@ import org.apache.james.mailbox.cassandra.CassandraMailboxSessionMapperFactory;
 import org.apache.james.mailbox.cassandra.DeleteMessageListener;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
-import org.apache.james.mailbox.cassandra.mail.CassandraACLDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
@@ -122,7 +122,7 @@ public class CassandraMailboxModule extends AbstractModule {
         bind(CassandraFirstUnseenDAO.class).in(Scopes.SINGLETON);
         bind(CassandraMailboxCounterDAO.class).in(Scopes.SINGLETON);
         bind(CassandraMailboxDAO.class).in(Scopes.SINGLETON);
-        bind(CassandraACLDAO.class).in(Scopes.SINGLETON);
+        bind(CassandraACLDAOV1.class).in(Scopes.SINGLETON);
         bind(CassandraMailboxPathDAOImpl.class).in(Scopes.SINGLETON);
         bind(CassandraMailboxPathV2DAO.class).in(Scopes.SINGLETON);
         bind(CassandraMailboxPathV3DAO.class).in(Scopes.SINGLETON);


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


[james-project] 01/13: JAMES-2543 updgrades MPT impl smtp to junit 5

Posted by bt...@apache.org.
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 b44a5ed3fe28e8a4e7f1fae7835c394ce1a98a40
Author: Jean Helou <jh...@codamens.fr>
AuthorDate: Mon Nov 30 21:59:40 2020 +0100

    JAMES-2543 updgrades MPT impl smtp to junit 5
---
 .../mpt/smtp/AwsS3RabbitMQForwardSmtpTest.java     |  32 ++--
 .../smtp/AwsS3RabbitMQSmtpStarttlsCommandTest.java |  29 ++--
 .../CassandraRabbitMQAwsS3SmtpTestRuleFactory.java |  21 ++-
 .../james/mpt/smtp/CassandraForwardSmtpTest.java   |  26 +++-
 .../mpt/smtp/CassandraSmtpStarttlsCommandTest.java |  18 +--
 .../mpt/smtp/CassandraSmtpTestRuleFactory.java     |  15 +-
 .../org/apache/james/mpt/smtp/ForwardSmtpTest.java |  50 +++---
 .../apache/james/mpt/smtp/SmtpAuthCommandTest.java |   5 -
 .../james/mpt/smtp/SmtpStarttlsCommandTest.java    |  29 ++--
 .../apache/james/mpt/smtp/SmtpTestExtension.java   | 159 +++++++++++++++++++
 .../org/apache/james/mpt/smtp/SmtpTestRule.java    | 137 -----------------
 server/testing/pom.xml                             |   4 +
 .../org/apache/james/utils/FakeSmtpExtension.java  | 168 +++++++++++++++++++++
 13 files changed, 443 insertions(+), 250 deletions(-)

diff --git a/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/AwsS3RabbitMQForwardSmtpTest.java b/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/AwsS3RabbitMQForwardSmtpTest.java
index 85b659d..f6621a9 100644
--- a/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/AwsS3RabbitMQForwardSmtpTest.java
+++ b/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/AwsS3RabbitMQForwardSmtpTest.java
@@ -21,27 +21,41 @@ package org.apache.james.mpt.smtp;
 
 import static org.apache.james.modules.protocols.SmtpGuiceProbe.SmtpServerConnectedType.SMTP_GLOBAL_SERVER;
 
+import org.apache.james.backends.cassandra.DockerCassandraExtension;
 import org.apache.james.backends.cassandra.DockerCassandraRule;
+import org.apache.james.blob.objectstorage.aws.DockerAwsS3Container;
+import org.apache.james.blob.objectstorage.aws.DockerAwsS3Extension;
+import org.apache.james.modules.AwsS3BlobStoreExtension;
 import org.apache.james.modules.objectstorage.aws.s3.DockerAwsS3TestRule;
 import org.junit.Rule;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.rules.RuleChain;
 import org.junit.rules.TestRule;
 
-public class AwsS3RabbitMQForwardSmtpTest extends ForwardSmtpTest {
+public class AwsS3RabbitMQForwardSmtpTest implements ForwardSmtpTest {
 
-    @Rule public DockerCassandraRule cassandraServer = new DockerCassandraRule();
+    @RegisterExtension
+    public static DockerCassandraExtension cassandraServer = new DockerCassandraExtension();
 
-    private DockerAwsS3TestRule dockerAwsS3TestRule = new DockerAwsS3TestRule();
+    @RegisterExtension
+    public AwsS3BlobStoreExtension dockerAwsS3TestRule = new AwsS3BlobStoreExtension();
 
-    private SmtpTestRule cassandraRabbitMQAwsS3SmtpTestRule =
-        CassandraRabbitMQAwsS3SmtpTestRuleFactory.create(SMTP_GLOBAL_SERVER, cassandraServer.getHost(), dockerAwsS3TestRule);
+    @RegisterExtension
+    public SmtpTestExtension cassandraRabbitMQAwsS3SmtpTestRule =
+            CassandraRabbitMQAwsS3SmtpTestRuleFactory.createExtension(SMTP_GLOBAL_SERVER, () -> cassandraServer.getDockerCassandra().getHost(), dockerAwsS3TestRule);
+
+    private SmtpHostSystem hostSystem;
+
+    @BeforeEach
+    void setup(SmtpHostSystem hostSystem) {
+        this.hostSystem = hostSystem;
+    }
 
-    @Rule
-    public TestRule composedRule = RuleChain.outerRule(dockerAwsS3TestRule).around(cassandraRabbitMQAwsS3SmtpTestRule);
 
     @Override
-    protected SmtpHostSystem createSmtpHostSystem() {
-        return cassandraRabbitMQAwsS3SmtpTestRule;
+    public SmtpHostSystem hostSystem() {
+        return hostSystem;
     }
 
 }
diff --git a/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/AwsS3RabbitMQSmtpStarttlsCommandTest.java b/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/AwsS3RabbitMQSmtpStarttlsCommandTest.java
index f3e31ab..d06d958 100644
--- a/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/AwsS3RabbitMQSmtpStarttlsCommandTest.java
+++ b/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/AwsS3RabbitMQSmtpStarttlsCommandTest.java
@@ -21,28 +21,19 @@ package org.apache.james.mpt.smtp;
 
 import static org.apache.james.modules.protocols.SmtpGuiceProbe.SmtpServerConnectedType.SMTP_START_TLS_SERVER;
 
-import org.apache.james.backends.cassandra.DockerCassandraRule;
-import org.apache.james.modules.objectstorage.aws.s3.DockerAwsS3TestRule;
-import org.junit.Rule;
-import org.junit.rules.RuleChain;
-import org.junit.rules.TestRule;
+import org.apache.james.backends.cassandra.DockerCassandraExtension;
+import org.apache.james.modules.AwsS3BlobStoreExtension;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class AwsS3RabbitMQSmtpStarttlsCommandTest extends SmtpStarttlsCommandTest {
 
-    @Rule public DockerCassandraRule cassandraServer = new DockerCassandraRule();
+    @RegisterExtension
+    public static DockerCassandraExtension cassandraServer = new DockerCassandraExtension();
 
+    @RegisterExtension
+    public AwsS3BlobStoreExtension dockerAwsS3TestRule = new AwsS3BlobStoreExtension();
 
-    private DockerAwsS3TestRule dockerAwsS3TestRule = new DockerAwsS3TestRule();
-
-    private SmtpTestRule cassandraRabbitMQAwsS3SmtpTestRule =
-        CassandraRabbitMQAwsS3SmtpTestRuleFactory.create(SMTP_START_TLS_SERVER, cassandraServer.getHost(), dockerAwsS3TestRule);
-
-    @Rule
-    public TestRule composedRule = RuleChain.outerRule(dockerAwsS3TestRule).around(cassandraRabbitMQAwsS3SmtpTestRule);
-
-    @Override
-    protected SmtpHostSystem createSmtpHostSystem() {
-        return cassandraRabbitMQAwsS3SmtpTestRule;
-    }
-
+    @RegisterExtension
+    public SmtpTestExtension cassandraRabbitMQAwsS3SmtpTestRule =
+            CassandraRabbitMQAwsS3SmtpTestRuleFactory.createExtension(SMTP_START_TLS_SERVER, () -> cassandraServer.getDockerCassandra().getHost(), dockerAwsS3TestRule);
 }
diff --git a/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/CassandraRabbitMQAwsS3SmtpTestRuleFactory.java b/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/CassandraRabbitMQAwsS3SmtpTestRuleFactory.java
index bb0bf7c..bd625dd 100644
--- a/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/CassandraRabbitMQAwsS3SmtpTestRuleFactory.java
+++ b/mpt/impl/smtp/cassandra-rabbitmq-object-storage/src/test/java/org/apache/james/mpt/smtp/CassandraRabbitMQAwsS3SmtpTestRuleFactory.java
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.james.mpt.smtp;
 
+import java.util.function.Supplier;
+
 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
 import org.apache.james.CassandraJamesServerMain;
 import org.apache.james.CleanupTasksPerformer;
@@ -30,10 +32,10 @@ import org.apache.james.blob.api.BlobStoreDAO;
 import org.apache.james.blob.api.MetricableBlobStore;
 import org.apache.james.blob.objectstorage.aws.S3BlobStoreDAO;
 import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.modules.AwsS3BlobStoreExtension;
 import org.apache.james.modules.TestRabbitMQModule;
 import org.apache.james.modules.mailbox.KeyspacesConfiguration;
 import org.apache.james.modules.objectstorage.DefaultBucketModule;
-import org.apache.james.modules.objectstorage.aws.s3.DockerAwsS3TestRule;
 import org.apache.james.modules.protocols.SmtpGuiceProbe.SmtpServerConnectedType;
 import org.apache.james.modules.queue.rabbitmq.RabbitMQModule;
 import org.apache.james.modules.server.CamelMailetContainerModule;
@@ -49,12 +51,13 @@ import com.google.inject.Module;
 import com.google.inject.name.Names;
 
 public final class CassandraRabbitMQAwsS3SmtpTestRuleFactory {
-    public static SmtpTestRule create(SmtpServerConnectedType smtpServerConnectedType, Host cassandraHost, DockerAwsS3TestRule awsS3TestRule) {
-        SmtpTestRule.ServerBuilder createJamesServer = (folder, dnsService) -> createJamesServer(cassandraHost, awsS3TestRule, folder, dnsService);
+    public static SmtpTestExtension createExtension(SmtpServerConnectedType smtpGlobalServer, Supplier<Host> host, AwsS3BlobStoreExtension dockerAwsS3TestRule) {
+        SmtpTestExtension.ServerBuilder createJamesServer = (folder, dnsService) -> createJamesServer(host, dockerAwsS3TestRule.getModule(), folder, dnsService);
 
-        return new SmtpTestRule(smtpServerConnectedType, createJamesServer);
+        return new SmtpTestExtension(smtpGlobalServer, createJamesServer);
     }
 
+
     private static Module BLOB_STORE_MODULE = new AbstractModule() {
         @Override
         protected void configure() {
@@ -65,23 +68,24 @@ public final class CassandraRabbitMQAwsS3SmtpTestRuleFactory {
         }
     };
 
-    private static GuiceJamesServer createJamesServer(Host cassandraHost, DockerAwsS3TestRule awsS3TestRule, TemporaryFolder folder, DNSService dnsService) throws Exception {
+    private static GuiceJamesServer createJamesServer(Supplier<Host> cassandraHost, Module awsS3Module , TemporaryFolder folder, DNSService dnsService) throws Exception {
         Configuration configuration = Configuration.builder()
             .workingDirectory(folder.newFolder())
             .configurationFromClasspath()
             .build();
 
+
         return GuiceJamesServer.forConfiguration(configuration)
             .combineWith(CassandraJamesServerMain.CASSANDRA_SERVER_CORE_MODULE,
                 new DefaultBucketModule(),
-                SmtpTestRule.SMTP_PROTOCOL_MODULE,
+                SmtpTestExtension.SMTP_PROTOCOL_MODULE,
                 binder -> binder.bind(MailQueueItemDecoratorFactory.class).to(RawMailQueueItemDecoratorFactory.class),
                 binder -> binder.bind(CamelMailetContainerModule.DefaultProcessorsConfigurationSupplier.class)
                     .toInstance(BaseHierarchicalConfiguration::new))
             .overrideWith(new RabbitMQModule(), BLOB_STORE_MODULE)
             .overrideWith(
                 new TestRabbitMQModule(DockerRabbitMQSingleton.SINGLETON),
-                awsS3TestRule.getModule(),
+                    awsS3Module,
                 binder -> binder.bind(KeyspacesConfiguration.class)
                     .toInstance(KeyspacesConfiguration.builder()
                         .keyspace(DockerCassandra.KEYSPACE)
@@ -90,10 +94,11 @@ public final class CassandraRabbitMQAwsS3SmtpTestRuleFactory {
                         .disableDurableWrites()
                         .build()),
                 binder -> binder.bind(ClusterConfiguration.class).toInstance(
-                    DockerCassandra.configurationBuilder(cassandraHost)
+                    DockerCassandra.configurationBuilder(cassandraHost.get())
                         .build()),
                 binder -> binder.bind(DNSService.class).toInstance(dnsService),
                 binder -> binder.bind(CleanupTasksPerformer.class).asEagerSingleton());
     }
+
 }
 
diff --git a/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraForwardSmtpTest.java b/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraForwardSmtpTest.java
index 21c8992..e2c8cdb 100644
--- a/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraForwardSmtpTest.java
+++ b/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraForwardSmtpTest.java
@@ -21,19 +21,29 @@ package org.apache.james.mpt.smtp;
 
 import static org.apache.james.modules.protocols.SmtpGuiceProbe.SmtpServerConnectedType.SMTP_GLOBAL_SERVER;
 
-import org.apache.james.backends.cassandra.DockerCassandraRule;
-import org.junit.Rule;
+import org.apache.james.backends.cassandra.DockerCassandraExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-public class CassandraForwardSmtpTest extends ForwardSmtpTest {
+public class CassandraForwardSmtpTest implements ForwardSmtpTest {
 
-    @Rule public DockerCassandraRule cassandraServer = new DockerCassandraRule();
+    @RegisterExtension
+    public static DockerCassandraExtension cassandraServer = new DockerCassandraExtension();
 
-    @Rule
-    public SmtpTestRule cassandraSmtpTestRule = CassandraSmtpTestRuleFactory.create(SMTP_GLOBAL_SERVER, cassandraServer.getHost());
+    @RegisterExtension
+    public SmtpTestExtension smtpTestExtension =
+            CassandraSmtpTestRuleFactory.createExtension(SMTP_GLOBAL_SERVER, () -> cassandraServer.getDockerCassandra().getHost());
+
+    private SmtpHostSystem hostSystem;
+
+    @BeforeEach
+    void setup(SmtpHostSystem hostSystem) {
+        this.hostSystem = hostSystem;
+    }
 
     @Override
-    protected SmtpHostSystem createSmtpHostSystem() {
-        return cassandraSmtpTestRule;
+    public SmtpHostSystem hostSystem() {
+        return hostSystem;
     }
 
 }
diff --git a/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraSmtpStarttlsCommandTest.java b/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraSmtpStarttlsCommandTest.java
index d7d1209..511a2ba 100644
--- a/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraSmtpStarttlsCommandTest.java
+++ b/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraSmtpStarttlsCommandTest.java
@@ -21,20 +21,16 @@ package org.apache.james.mpt.smtp;
 
 import static org.apache.james.modules.protocols.SmtpGuiceProbe.SmtpServerConnectedType.SMTP_START_TLS_SERVER;
 
-import org.apache.james.backends.cassandra.DockerCassandraRule;
-import org.junit.Rule;
+import org.apache.james.backends.cassandra.DockerCassandraExtension;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 public class CassandraSmtpStarttlsCommandTest extends SmtpStarttlsCommandTest {
 
-    @Rule public DockerCassandraRule cassandraServer = new DockerCassandraRule();
-
-    @Rule
-    public SmtpTestRule cassandraSmtpTestRule = CassandraSmtpTestRuleFactory.create(SMTP_START_TLS_SERVER, cassandraServer.getHost());
-
-    @Override
-    protected SmtpHostSystem createSmtpHostSystem() {
-        return cassandraSmtpTestRule;
-    }
+    @RegisterExtension
+    public static DockerCassandraExtension cassandraServer = new DockerCassandraExtension();
 
+    @RegisterExtension
+    public SmtpTestExtension smtpTestExtension =
+            CassandraSmtpTestRuleFactory.createExtension(SMTP_START_TLS_SERVER, () -> cassandraServer.getDockerCassandra().getHost());
 
 }
diff --git a/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraSmtpTestRuleFactory.java b/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraSmtpTestRuleFactory.java
index cddc8dd..a5a5954 100644
--- a/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraSmtpTestRuleFactory.java
+++ b/mpt/impl/smtp/cassandra/src/test/java/org/apache/james/mpt/smtp/CassandraSmtpTestRuleFactory.java
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.james.mpt.smtp;
 
+import java.util.function.Supplier;
+
 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
 import org.apache.james.CassandraJamesServerMain;
 import org.apache.james.GuiceJamesServer;
@@ -36,13 +38,14 @@ import org.apache.james.util.Host;
 import org.junit.rules.TemporaryFolder;
 
 public final class CassandraSmtpTestRuleFactory {
-    public static SmtpTestRule create(SmtpServerConnectedType smtpServerConnectedType, Host cassandraHost) {
-        SmtpTestRule.ServerBuilder createJamesServer = (folder, dnsService) -> createJamesServer(cassandraHost, folder, dnsService);
 
-        return new SmtpTestRule(smtpServerConnectedType, createJamesServer);
+    public static SmtpTestExtension createExtension(SmtpServerConnectedType smtpServerConnectedType, Supplier<Host> cassandraHost) {
+        SmtpTestExtension.ServerBuilder createJamesServer = (folder, dnsService) -> createJamesServer(cassandraHost, folder, dnsService);
+
+        return new SmtpTestExtension(smtpServerConnectedType, createJamesServer);
     }
 
-    private static GuiceJamesServer createJamesServer(Host cassandraHost, TemporaryFolder folder, DNSService dnsService) throws Exception {
+    private static GuiceJamesServer createJamesServer(Supplier<Host> cassandraHost, TemporaryFolder folder, DNSService dnsService) throws Exception {
         Configuration configuration = Configuration.builder()
             .workingDirectory(folder.newFolder())
             .configurationFromClasspath()
@@ -52,13 +55,13 @@ public final class CassandraSmtpTestRuleFactory {
             .combineWith(CassandraJamesServerMain.CASSANDRA_SERVER_CORE_MODULE,
                 new CassandraBlobStoreModule(),
                 new CassandraBucketModule(),
-                SmtpTestRule.SMTP_PROTOCOL_MODULE,
+                SmtpTestExtension.SMTP_PROTOCOL_MODULE,
                 binder -> binder.bind(MailQueueItemDecoratorFactory.class).to(RawMailQueueItemDecoratorFactory.class),
                 binder -> binder.bind(CamelMailetContainerModule.DefaultProcessorsConfigurationSupplier.class)
                     .toInstance(BaseHierarchicalConfiguration::new))
             .overrideWith(
                 binder -> binder.bind(ClusterConfiguration.class).toInstance(
-                    DockerCassandra.configurationBuilder(cassandraHost)
+                    DockerCassandra.configurationBuilder(cassandraHost.get())
                         .build()),
                 binder -> binder.bind(KeyspacesConfiguration.class)
                     .toInstance(KeyspacesConfiguration.builder()
diff --git a/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/ForwardSmtpTest.java b/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/ForwardSmtpTest.java
index b885f7a..8092e07 100644
--- a/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/ForwardSmtpTest.java
+++ b/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/ForwardSmtpTest.java
@@ -25,48 +25,40 @@ import static org.hamcrest.Matchers.equalTo;
 import java.util.Locale;
 
 import org.apache.james.mpt.script.SimpleScriptedTestProtocol;
-import org.apache.james.utils.FakeSmtp;
+import org.apache.james.utils.FakeSmtpExtension;
 import org.awaitility.Awaitility;
 import org.awaitility.Duration;
 import org.awaitility.core.ConditionFactory;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-public abstract class ForwardSmtpTest {
 
-    public static final String USER = "bob";
-    public static final String DOMAIN = "mydomain.tld";
-    public static final String USER_AT_DOMAIN = USER + "@" + DOMAIN;
-    public static final String PASSWORD = "secret";
-    public static final Duration slowPacedPollInterval = ONE_HUNDRED_MILLISECONDS;
-    public static final ConditionFactory calmlyAwait = Awaitility.with()
+public interface ForwardSmtpTest {
+
+    String USER = "bob";
+    String DOMAIN = "mydomain.tld";
+    String USER_AT_DOMAIN = USER + "@" + DOMAIN;
+    String PASSWORD = "secret";
+    Duration slowPacedPollInterval = ONE_HUNDRED_MILLISECONDS;
+    ConditionFactory calmlyAwait = Awaitility.with()
         .pollInterval(slowPacedPollInterval)
         .await();
 
-    @ClassRule
-    public static FakeSmtp fakeSmtp = FakeSmtp.withDefaultPort();
-
-    protected abstract SmtpHostSystem createSmtpHostSystem();
-    
-    private SmtpHostSystem hostSystem;
-    private SimpleScriptedTestProtocol scriptedTest;
+    @RegisterExtension
+    FakeSmtpExtension fakeSmtp = FakeSmtpExtension.withDefaultPort();
 
-    @Before
-    public void setUp() throws Exception {
-        hostSystem = createSmtpHostSystem();
+    SmtpHostSystem hostSystem();
 
-        scriptedTest = new SimpleScriptedTestProtocol("/org/apache/james/smtp/scripts/", hostSystem)
+    @Test
+    default void forwardingAnEmailShouldWork(FakeSmtpExtension.FakeSmtp fakeSmtp) throws Exception {
+        SimpleScriptedTestProtocol scriptedTest = new SimpleScriptedTestProtocol("/org/apache/james/smtp/scripts/", hostSystem())
                 .withLocale(Locale.US)
                 .withUser(USER_AT_DOMAIN, PASSWORD);
-        
-        hostSystem.getInMemoryDnsService()
-            .registerMxRecord("yopmail.com", fakeSmtp.getContainer().getContainerIp());
-        hostSystem.addAddressMapping(USER, DOMAIN, "ray@yopmail.com");
-    }
 
-    @Test
-    public void forwardingAnEmailShouldWork() throws Exception {
+        hostSystem().getInMemoryDnsService()
+                .registerMxRecord("yopmail.com", fakeSmtp.getContainerIp());
+        hostSystem().addAddressMapping(USER, DOMAIN, "ray@yopmail.com");
+
         scriptedTest.run("helo");
 
         calmlyAwait.atMost(TWO_MINUTES).untilAsserted(() ->
diff --git a/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpAuthCommandTest.java b/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpAuthCommandTest.java
index 4071696..f45a7bd 100644
--- a/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpAuthCommandTest.java
+++ b/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpAuthCommandTest.java
@@ -22,9 +22,7 @@ import java.util.Locale;
 
 import org.apache.james.mpt.script.SimpleScriptedTestProtocol;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
 
 public abstract class SmtpAuthCommandTest {
 
@@ -33,9 +31,6 @@ public abstract class SmtpAuthCommandTest {
     public static final String USER_AT_DOMAIN = USER + "@" + DOMAIN;
     public static final String PASSWORD = "secret";
 
-    @Rule
-    public final TemporaryFolder folder = new TemporaryFolder();
-
     protected abstract SmtpHostSystem createSmtpHostSystem();
     
     private SmtpHostSystem hostSystem;
diff --git a/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpStarttlsCommandTest.java b/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpStarttlsCommandTest.java
index a0c110e..89925b6 100644
--- a/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpStarttlsCommandTest.java
+++ b/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpStarttlsCommandTest.java
@@ -21,10 +21,8 @@ package org.apache.james.mpt.smtp;
 import java.util.Locale;
 
 import org.apache.james.mpt.script.SimpleScriptedTestProtocol;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 public abstract class SmtpStarttlsCommandTest {
 
@@ -33,17 +31,12 @@ public abstract class SmtpStarttlsCommandTest {
     public static final String USER_AT_DOMAIN = USER + "@" + DOMAIN;
     public static final String PASSWORD = "secret";
 
-    @Rule
-    public final TemporaryFolder folder = new TemporaryFolder();
-
-    protected abstract SmtpHostSystem createSmtpHostSystem();
-    
-    private SmtpHostSystem hostSystem;
+    protected SmtpHostSystem hostSystem;
     private SimpleScriptedTestProtocol scriptedTest;
 
-    @Before
-    public void setUp() throws Exception {
-        hostSystem = createSmtpHostSystem();
+    @BeforeEach
+    public void setUp(SmtpHostSystem hostSystem) throws Exception {
+        this.hostSystem = hostSystem;
         String scriptDir = "/org/apache/james/smtp/scripts/";
         scriptedTest = new SimpleScriptedTestProtocol(scriptDir, hostSystem)
                 .withLocale(Locale.US)
@@ -51,29 +44,29 @@ public abstract class SmtpStarttlsCommandTest {
     }
 
     @Test
-    public void starttlsShouldWork() throws Exception {
+    void starttlsShouldWork() throws Exception {
         scriptedTest.run("starttls");
     }
 
     @Test
-    public void starttlsShouldBeRejectedWhenFollowedByCommand() throws Exception {
+    void starttlsShouldBeRejectedWhenFollowedByCommand() throws Exception {
         scriptedTest.run("starttls_with_injection");
     }
 
     @Test
-    public void shouldNotRejectContentWithStartTls() throws Exception {
+    void shouldNotRejectContentWithStartTls() throws Exception {
         scriptedTest.run("data_with_starttls");
     }
 
 
     @Test
-    public void shouldNotRejectRcptWithStartTls() throws Exception {
+    void shouldNotRejectRcptWithStartTls() throws Exception {
         scriptedTest.withUser("starttls@mydomain.tld", PASSWORD);
         scriptedTest.run("rcpt_with_starttls");
     }
 
     @Test
-    public void shouldNotRejectContentStartsWithStartTls() throws Exception {
+    void shouldNotRejectContentStartsWithStartTls() throws Exception {
         scriptedTest.run("data_starts_with_starttls");
     }
 }
diff --git a/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpTestExtension.java b/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpTestExtension.java
new file mode 100644
index 0000000..aef6692
--- /dev/null
+++ b/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpTestExtension.java
@@ -0,0 +1,159 @@
+/****************************************************************
+ * 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.mpt.smtp;
+
+import java.util.Optional;
+
+import org.apache.james.GuiceJamesServer;
+import org.apache.james.core.Domain;
+import org.apache.james.core.Username;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.InMemoryDNSService;
+import org.apache.james.modules.protocols.ProtocolHandlerModule;
+import org.apache.james.modules.protocols.SMTPServerModule;
+import org.apache.james.modules.protocols.SmtpGuiceProbe;
+import org.apache.james.mpt.api.Continuation;
+import org.apache.james.mpt.api.Session;
+import org.apache.james.mpt.monitor.SystemLoggingMonitor;
+import org.apache.james.mpt.session.ExternalSessionFactory;
+import org.apache.james.util.Port;
+import org.apache.james.utils.DataProbeImpl;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+import org.junit.rules.TemporaryFolder;
+
+import com.google.common.base.Preconditions;
+import com.google.inject.Module;
+import com.google.inject.util.Modules;
+
+
+public class SmtpTestExtension implements
+        BeforeEachCallback,
+        AfterEachCallback,
+        ParameterResolver {
+
+    @FunctionalInterface
+    public interface ServerBuilder {
+        GuiceJamesServer build(TemporaryFolder folder, DNSService dnsService) throws Exception;
+    }
+
+    public static final Module SMTP_PROTOCOL_MODULE = Modules.combine(
+            new ProtocolHandlerModule(),
+            new SMTPServerModule());
+
+    private final SmtpGuiceProbe.SmtpServerConnectedType smtpServerConnectedType;
+    private final ServerBuilder createJamesServer;
+    private TemporaryFolder folder;
+    private InMemoryDNSService inMemoryDNSService;
+    private GuiceJamesServer jamesServer;
+    private SmtpHostSystem smtpHostSystem;
+
+    public SmtpTestExtension(SmtpGuiceProbe.SmtpServerConnectedType smtpServerConnectedType, ServerBuilder createJamesServer) {
+        this.smtpServerConnectedType = smtpServerConnectedType;
+        this.createJamesServer = createJamesServer;
+    }
+
+    @Override
+    public void beforeEach(ExtensionContext context) throws Exception {
+        inMemoryDNSService = new InMemoryDNSService();
+        folder = new TemporaryFolder();
+        folder.create();
+        jamesServer = createJamesServer.build(folder, inMemoryDNSService);
+        jamesServer.start();
+        smtpHostSystem = new HostSystem(jamesServer, smtpServerConnectedType, inMemoryDNSService);
+    }
+
+    @Override
+    public void afterEach(ExtensionContext context) throws Exception {
+        jamesServer.stop();
+        folder.delete();
+    }
+
+    @Override
+    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return (parameterContext.getParameter().getType().isAssignableFrom(SmtpHostSystem.class));
+    }
+
+    @Override
+    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return smtpHostSystem;
+    }
+
+
+    public static class HostSystem implements SmtpHostSystem {
+
+        private final ExternalSessionFactory sessionFactory;
+        private final SmtpGuiceProbe.SmtpServerConnectedType smtpServerConnectedType;
+        private final InMemoryDNSService inMemoryDNSService;
+        private final GuiceJamesServer jamesServer;
+
+        public HostSystem(GuiceJamesServer jamesServer, SmtpGuiceProbe.SmtpServerConnectedType smtpServerConnectedType, InMemoryDNSService inMemoryDNSService) {
+            this.jamesServer = jamesServer;
+            this.smtpServerConnectedType = smtpServerConnectedType;
+            this.inMemoryDNSService = inMemoryDNSService;
+            SmtpGuiceProbe smtpProbe = jamesServer.getProbe(SmtpGuiceProbe.class);
+            Port smtpPort = this.smtpServerConnectedType.getPortExtractor().apply(smtpProbe);
+            sessionFactory = new ExternalSessionFactory("localhost", smtpPort, new SystemLoggingMonitor(), "220 mydomain.tld smtp");
+        }
+
+        @Override
+        public boolean addUser(Username userAtDomain, String password) throws Exception {
+            Optional<Domain> domain = userAtDomain.getDomainPart();
+            Preconditions.checkArgument(domain.isPresent(), "The 'user' should contain the 'domain'");
+            createDomainIfNeeded(domain.get().asString());
+            jamesServer.getProbe(DataProbeImpl.class).addUser(userAtDomain.asString(), password);
+            return true;
+        }
+
+        @Override
+        public Session newSession(Continuation continuation) throws Exception {
+            return sessionFactory.newSession(continuation);
+        }
+
+        private void createDomainIfNeeded(String domain) throws Exception {
+            if (!jamesServer.getProbe(DataProbeImpl.class).containsDomain(domain)) {
+                jamesServer.getProbe(DataProbeImpl.class).addDomain(domain);
+            }
+        }
+
+        @Override
+        public void addAddressMapping(String user, String domain, String address) throws Exception {
+            jamesServer.getProbe(DataProbeImpl.class).addAddressMapping(user, domain, address);
+        }
+
+        @Override
+        public void beforeTest() throws Exception {
+
+        }
+
+        @Override
+        public void afterTest() throws Exception {
+
+        }
+
+        @Override
+        public InMemoryDNSService getInMemoryDnsService() {
+            return inMemoryDNSService;
+        }
+    }
+}
diff --git a/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpTestRule.java b/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpTestRule.java
deleted file mode 100644
index 9162099..0000000
--- a/mpt/impl/smtp/core/src/main/java/org/apache/james/mpt/smtp/SmtpTestRule.java
+++ /dev/null
@@ -1,137 +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.mpt.smtp;
-
-import java.util.Optional;
-
-import org.apache.james.GuiceJamesServer;
-import org.apache.james.core.Domain;
-import org.apache.james.core.Username;
-import org.apache.james.dnsservice.api.DNSService;
-import org.apache.james.dnsservice.api.InMemoryDNSService;
-import org.apache.james.modules.protocols.ProtocolHandlerModule;
-import org.apache.james.modules.protocols.SMTPServerModule;
-import org.apache.james.modules.protocols.SmtpGuiceProbe;
-import org.apache.james.mpt.api.Continuation;
-import org.apache.james.mpt.api.Session;
-import org.apache.james.mpt.monitor.SystemLoggingMonitor;
-import org.apache.james.mpt.session.ExternalSessionFactory;
-import org.apache.james.util.Port;
-import org.apache.james.utils.DataProbeImpl;
-import org.junit.rules.TemporaryFolder;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import com.google.common.base.Preconditions;
-import com.google.inject.Module;
-import com.google.inject.util.Modules;
-
-
-public class SmtpTestRule implements TestRule, SmtpHostSystem {
-    @FunctionalInterface
-    public interface ServerBuilder {
-        GuiceJamesServer build(TemporaryFolder folder, DNSService dnsService) throws Exception;
-    }
-
-    public static final Module SMTP_PROTOCOL_MODULE = Modules.combine(
-        new ProtocolHandlerModule(),
-        new SMTPServerModule());
-
-    private final SmtpGuiceProbe.SmtpServerConnectedType smtpServerConnectedType;
-    private final ServerBuilder createJamesServer;
-    private TemporaryFolder folder;
-    private InMemoryDNSService inMemoryDNSService;
-    private GuiceJamesServer jamesServer;
-    private ExternalSessionFactory sessionFactory;
-
-    public SmtpTestRule(SmtpGuiceProbe.SmtpServerConnectedType smtpServerConnectedType, ServerBuilder createJamesServer) {
-        this.smtpServerConnectedType = smtpServerConnectedType;
-        this.createJamesServer = createJamesServer;
-    }
-
-    @Override
-    public Statement apply(Statement base, Description description) {
-        return new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                beforeTest();
-                try {
-                    base.evaluate();
-                } finally {
-                    afterTest();
-                }
-            }
-        };
-    }
-
-    @Override
-    public boolean addUser(Username userAtDomain, String password) throws Exception {
-        Optional<Domain> domain = userAtDomain.getDomainPart();
-        Preconditions.checkArgument(domain.isPresent(), "The 'user' should contain the 'domain'");
-        createDomainIfNeeded(domain.get().asString());
-        jamesServer.getProbe(DataProbeImpl.class).addUser(userAtDomain.asString(), password);
-        return true;
-    }
-
-    @Override
-    public Session newSession(Continuation continuation) throws Exception {
-        return sessionFactory.newSession(continuation);
-    }
-
-    private void createDomainIfNeeded(String domain) throws Exception {
-        if (!jamesServer.getProbe(DataProbeImpl.class).containsDomain(domain)) {
-            jamesServer.getProbe(DataProbeImpl.class).addDomain(domain);
-        }
-    }
-
-    @Override
-    public void addAddressMapping(String user, String domain, String address) throws Exception {
-        jamesServer.getProbe(DataProbeImpl.class).addAddressMapping(user, domain, address);
-    }
-
-    @Override
-    public void beforeTest() throws Exception {
-        inMemoryDNSService = new InMemoryDNSService();
-        folder = new TemporaryFolder();
-        folder.create();
-        jamesServer = createJamesServer.build(folder, inMemoryDNSService);
-        jamesServer.start();
-
-        createSessionFactory();
-    }
-
-    @Override
-    public void afterTest() {
-        jamesServer.stop();
-        folder.delete();
-    }
-
-    @Override
-    public InMemoryDNSService getInMemoryDnsService() {
-        return inMemoryDNSService;
-    }
-
-    private void createSessionFactory() {
-        SmtpGuiceProbe smtpProbe = jamesServer.getProbe(SmtpGuiceProbe.class);
-        Port smtpPort = smtpServerConnectedType.getPortExtractor().apply(smtpProbe);
-
-        sessionFactory = new ExternalSessionFactory("localhost", smtpPort, new SystemLoggingMonitor(), "220 mydomain.tld smtp");
-    }
-}
diff --git a/server/testing/pom.xml b/server/testing/pom.xml
index 6c8d522..e991f0c 100644
--- a/server/testing/pom.xml
+++ b/server/testing/pom.xml
@@ -74,6 +74,10 @@
             <artifactId>awaitility</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.subethamail</groupId>
             <artifactId>subethasmtp</artifactId>
             <scope>test</scope>
diff --git a/server/testing/src/main/java/org/apache/james/utils/FakeSmtpExtension.java b/server/testing/src/main/java/org/apache/james/utils/FakeSmtpExtension.java
new file mode 100644
index 0000000..a2f59c3
--- /dev/null
+++ b/server/testing/src/main/java/org/apache/james/utils/FakeSmtpExtension.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.utils;
+
+import static io.restassured.RestAssured.given;
+import static io.restassured.config.EncoderConfig.encoderConfig;
+import static io.restassured.config.RestAssuredConfig.newConfig;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.function.Consumer;
+
+import org.apache.james.util.docker.Images;
+import org.apache.james.util.docker.RateLimiters;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy;
+
+import com.github.dockerjava.api.model.ContainerNetwork;
+
+import io.restassured.builder.RequestSpecBuilder;
+import io.restassured.builder.ResponseSpecBuilder;
+import io.restassured.http.ContentType;
+import io.restassured.response.ValidatableResponse;
+import io.restassured.specification.RequestSpecification;
+import io.restassured.specification.ResponseSpecification;
+
+
+public class FakeSmtpExtension implements
+        BeforeEachCallback,
+        AfterEachCallback,
+        ParameterResolver {
+
+    private static final int SMTP_PORT = 25;
+
+    public static FakeSmtpExtension withSmtpPort(Integer smtpPort) {
+        GenericContainer<?> container = fakeSmtpContainer()
+                .withExposedPorts(smtpPort)
+                .withCommand("node", "cli", "--listen", "80", "--smtp", smtpPort.toString());
+
+        return new FakeSmtpExtension(container);
+    }
+
+    public static FakeSmtpExtension withDefaultPort() {
+        return withSmtpPort(SMTP_PORT);
+    }
+
+    private static  GenericContainer<?> fakeSmtpContainer() {
+        return new GenericContainer<>(Images.FAKE_SMTP)
+            .waitingFor(new HostPortWaitStrategy()
+                .withRateLimiter(RateLimiters.TWENTIES_PER_SECOND)
+                .withStartupTimeout(Duration.ofMinutes(1))
+            );
+    }
+
+    private final GenericContainer<?> container;
+    private final FakeSmtp fakeSmtp;
+
+    private FakeSmtpExtension(GenericContainer<?> container) {
+        this.container = container;
+        this.fakeSmtp = new FakeSmtp(container);
+    }
+
+    @Override
+    public void beforeEach(ExtensionContext context) throws Exception {
+        container.start();
+    }
+
+    @Override
+    public void afterEach(ExtensionContext context) throws Exception {
+        container.stop();
+    }
+
+    @Override
+    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return (parameterContext.getParameter().getType().isAssignableFrom(FakeSmtp.class));
+    }
+
+    @Override
+    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return fakeSmtp;
+    }
+
+    public static class FakeSmtp {
+        public static final ResponseSpecification RESPONSE_SPECIFICATION = new ResponseSpecBuilder().build();
+
+        private final GenericContainer<?> container;
+
+        public FakeSmtp(GenericContainer<?> container) {
+            this.container = container;
+        }
+
+        public String getContainerIp() {
+            return container.getContainerInfo()
+                    .getNetworkSettings()
+                    .getNetworks()
+                    .values()
+                    .stream()
+                    .map(ContainerNetwork::getIpAddress)
+                    .findFirst()
+                    .orElseThrow(IllegalStateException::new);
+        }
+
+        private String getHostIp() {
+            return container.getContainerIpAddress();
+        }
+
+        public void assertEmailReceived(Consumer<ValidatableResponse> expectations) {
+            expectations.accept(
+                    given(requestSpecification(), RESPONSE_SPECIFICATION)
+                            .get("/api/email")
+                            .then()
+                            .statusCode(200));
+        }
+
+        private RequestSpecification requestSpecification() {
+            return new RequestSpecBuilder()
+                    .setContentType(ContentType.JSON)
+                    .setAccept(ContentType.JSON)
+                    .setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(StandardCharsets.UTF_8)))
+                    .setPort(80)
+                    .setBaseUri("http://" + getContainerIp())
+                    .build();
+        }
+
+        public void clean() {
+            clean(requestSpecification());
+        }
+
+        private static void clean(RequestSpecification requestSpecification) {
+            given(requestSpecification, RESPONSE_SPECIFICATION)
+                    .get("/api/email")
+                    .jsonPath()
+                    .getList("id", String.class)
+                    .stream()
+                    .mapToInt(Integer::valueOf)
+                    .max()
+                    .ifPresent(id -> given(requestSpecification, RESPONSE_SPECIFICATION)
+                            .get("/api/email/purge/" + id));
+        }
+
+        public GenericContainer<?> getContainer() {
+            return container;
+        }
+    }
+}


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


[james-project] 08/13: JAMES-3435 CassandraACLDAOV2 no longer need to return ACLDiffs upon updates

Posted by bt...@apache.org.
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 38024f9566c820bd1b6a84a3e9359a1e65017f99
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sat Dec 5 08:39:19 2020 +0700

    JAMES-3435 CassandraACLDAOV2 no longer need to return ACLDiffs upon updates
    
    The event sourcing system wrapping CassandraACLDAOV2 updates already takes care of it.
---
 .../mailbox/cassandra/mail/CassandraACLDAO.java    | 42 ----------------------
 .../mailbox/cassandra/mail/CassandraACLDAOV1.java  |  2 +-
 .../mailbox/cassandra/mail/CassandraACLDAOV2.java  | 23 +++---------
 .../mailbox/cassandra/mail/utils/GuiceUtils.java   |  1 -
 4 files changed, 6 insertions(+), 62 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAO.java
deleted file mode 100644
index 627baec..0000000
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAO.java
+++ /dev/null
@@ -1,42 +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.mailbox.cassandra.mail;
-
-import java.util.function.Supplier;
-
-import org.apache.james.mailbox.acl.ACLDiff;
-import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.model.MailboxACL;
-
-import reactor.core.publisher.Mono;
-
-public interface CassandraACLDAO {
-    interface CassandraACLDAOSupplier extends Supplier<CassandraACLDAO> {
-
-    }
-
-    Mono<Void> delete(CassandraId cassandraId);
-
-    Mono<MailboxACL> getACL(CassandraId cassandraId);
-
-    Mono<ACLDiff> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command);
-
-    Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL);
-}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV1.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV1.java
index 3bd9c47..db5eb86 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV1.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV1.java
@@ -54,7 +54,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 
 import reactor.core.publisher.Mono;
 
-public class CassandraACLDAOV1 implements CassandraACLDAO {
+public class CassandraACLDAOV1 {
     public static final int INITIAL_VALUE = 0;
     private static final Logger LOG = LoggerFactory.getLogger(CassandraACLDAOV1.class);
     private static final String OLD_VERSION = "oldVersion";
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
index c9e6339..8357650 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
@@ -31,7 +31,6 @@ import javax.inject.Inject;
 
 import org.apache.commons.lang3.NotImplementedException;
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
 import org.apache.james.mailbox.cassandra.table.CassandraACLV2Table;
@@ -49,7 +48,7 @@ import com.google.common.collect.ImmutableSet;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
-public class CassandraACLDAOV2 implements CassandraACLDAO {
+public class CassandraACLDAOV2 {
     private final CassandraAsyncExecutor executor;
     private final PreparedStatement insertRights;
     private final PreparedStatement removeRights;
@@ -125,26 +124,14 @@ public class CassandraACLDAOV2 implements CassandraACLDAO {
             .reduce(Throwing.biFunction(MailboxACL::union));
     }
 
-    public Mono<ACLDiff> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
-        return getACL(cassandraId)
-            .switchIfEmpty(Mono.just(new MailboxACL()))
-            .flatMap(before -> doUpdateACL(cassandraId, command)
-                .then(getACL(cassandraId)
-                    .switchIfEmpty(Mono.just(new MailboxACL()))
-                    .map(after -> ACLDiff.computeDiff(before, after))));
-    }
-
-    public Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
-        return getACL(cassandraId)
-            .switchIfEmpty(Mono.just(MailboxACL.EMPTY))
-            .flatMap(oldACL -> delete(cassandraId)
+    public Mono<Void> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
+        return delete(cassandraId)
                 .then(Flux.fromIterable(mailboxACL.getEntries().entrySet())
                     .concatMap(entry -> doSetACL(cassandraId, mailboxACL))
-                    .then())
-                .thenReturn(ACLDiff.computeDiff(oldACL, mailboxACL)));
+                    .then());
     }
 
-    private Mono<Void> doUpdateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
+    public Mono<Void> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
         ImmutableSet<String> rightStrings = asStringSet(command.getRights());
         switch (command.getEditMode()) {
             case ADD:
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
index ad7fa95..bb2d0c7 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
@@ -38,7 +38,6 @@ import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTOModule;
 import org.apache.james.json.DTO;
 import org.apache.james.json.DTOModule;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
-import org.apache.james.mailbox.cassandra.mail.CassandraACLDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
 import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.model.MessageId;


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


[james-project] 06/13: JAMES-2393 Dispatching an EventSourcing command can return the generated events

Posted by bt...@apache.org.
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 9449c8353182e4634bfd1bf5f586fdb2697558d5
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Dec 4 12:00:20 2020 +0700

    JAMES-2393 Dispatching an EventSourcing command can return the generated events
    
    This enables reusing the state of the transaction
---
 .../apache/james/eventsourcing/CommandDispatcher.scala    | 10 ++++------
 .../apache/james/eventsourcing/EventSourcingSystem.scala  |  4 +++-
 .../mailing/listeners/QuotaThresholdCrossingListener.java |  3 ++-
 .../filtering/impl/EventSourcingFilteringManagement.java  |  2 +-
 .../james/task/eventsourcing/WorkerStatusListener.scala   | 15 +++++++--------
 5 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/event-sourcing/event-sourcing-core/src/main/scala/org/apache/james/eventsourcing/CommandDispatcher.scala b/event-sourcing/event-sourcing-core/src/main/scala/org/apache/james/eventsourcing/CommandDispatcher.scala
index 05abc6f..a547bc4 100644
--- a/event-sourcing/event-sourcing-core/src/main/scala/org/apache/james/eventsourcing/CommandDispatcher.scala
+++ b/event-sourcing/event-sourcing-core/src/main/scala/org/apache/james/eventsourcing/CommandDispatcher.scala
@@ -20,12 +20,10 @@ package org.apache.james.eventsourcing
 
 import java.util
 
+import com.google.common.base.Preconditions
 import javax.inject.Inject
-
 import org.apache.james.eventsourcing.eventstore.EventStoreFailedException
 import org.reactivestreams.Publisher
-
-import com.google.common.base.Preconditions
 import reactor.core.scala.publisher.SMono
 
 import scala.jdk.CollectionConverters._
@@ -51,7 +49,7 @@ object CommandDispatcher {
 class CommandDispatcher @Inject()(eventBus: EventBus, handlers: Set[CommandHandler[_ <: Command]]) {
   Preconditions.checkArgument(hasOnlyOneHandlerByCommand(handlers), CommandDispatcher.ONLY_ONE_HANDLER_PRECONDITION)
 
-  def dispatch(c: Command): Publisher[Void] = {
+  def dispatch(c: Command): Publisher[util.List[_ <: Event]] = {
     tryDispatch(c)
       .retry(CommandDispatcher.MAX_RETRY, {
         case _: EventStoreFailedException => true
@@ -71,11 +69,11 @@ class CommandDispatcher @Inject()(eventBus: EventBus, handlers: Set[CommandHandl
   private val handlersByClass: Map[Class[_ <: Command], CommandHandler[_ <: Command]] =
     handlers.map(handler => (handler.handledClass, handler)).toMap
 
-  private def tryDispatch(c: Command): SMono[Void] = {
+  private def tryDispatch(c: Command): SMono[util.List[_ <: Event]] = {
     handleCommand(c) match {
       case Some(eventsPublisher) =>
         SMono(eventsPublisher)
-          .flatMap(events => eventBus.publish(events.asScala))
+          .flatMap(events => eventBus.publish(events.asScala).`then`(SMono.just(events)))
       case _ =>
         SMono.raiseError(CommandDispatcher.UnknownCommandException(c))
     }
diff --git a/event-sourcing/event-sourcing-core/src/main/scala/org/apache/james/eventsourcing/EventSourcingSystem.scala b/event-sourcing/event-sourcing-core/src/main/scala/org/apache/james/eventsourcing/EventSourcingSystem.scala
index 5cc52f2..804aa17 100644
--- a/event-sourcing/event-sourcing-core/src/main/scala/org/apache/james/eventsourcing/EventSourcingSystem.scala
+++ b/event-sourcing/event-sourcing-core/src/main/scala/org/apache/james/eventsourcing/EventSourcingSystem.scala
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.james.eventsourcing
 
+import java.util
+
 import org.apache.james.eventsourcing.eventstore.EventStore
 import org.reactivestreams.Publisher
 
@@ -37,5 +39,5 @@ class EventSourcingSystem(handlers: Set[CommandHandler[_ <: Command]],
   private val eventBus = new EventBus(eventStore, subscribers)
   private val commandDispatcher = new CommandDispatcher(eventBus, handlers)
 
-  def dispatch(c: Command): Publisher[Void] = commandDispatcher.dispatch(c)
+  def dispatch(c: Command): Publisher[util.List[_ <: Event]] = commandDispatcher.dispatch(c)
 }
\ No newline at end of file
diff --git a/mailbox/plugin/quota-mailing/src/main/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListener.java b/mailbox/plugin/quota-mailing/src/main/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListener.java
index d705740..7c9760c 100644
--- a/mailbox/plugin/quota-mailing/src/main/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListener.java
+++ b/mailbox/plugin/quota-mailing/src/main/java/org/apache/james/mailbox/quota/mailing/listeners/QuotaThresholdCrossingListener.java
@@ -89,6 +89,7 @@ public class QuotaThresholdCrossingListener implements MailboxListener.ReactiveG
 
     private Mono<Void> handleEvent(Username username, QuotaUsageUpdatedEvent event) {
         return Mono.from(eventSourcingSystem.dispatch(
-            new DetectThresholdCrossing(username, event.getCountQuota(), event.getSizeQuota(), event.getInstant())));
+                new DetectThresholdCrossing(username, event.getCountQuota(), event.getSizeQuota(), event.getInstant())))
+            .then();
     }
 }
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java
index 662fad1..485c194 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java
@@ -54,7 +54,7 @@ public class EventSourcingFilteringManagement implements FilteringManagement {
 
     @Override
     public Publisher<Void> defineRulesForUser(Username username, List<Rule> rules) {
-        return eventSourcingSystem.dispatch(new DefineRulesCommand(username, rules));
+        return Mono.from(eventSourcingSystem.dispatch(new DefineRulesCommand(username, rules))).then();
     }
 
     @Override
diff --git a/server/task/task-memory/src/main/scala/org/apache/james/task/eventsourcing/WorkerStatusListener.scala b/server/task/task-memory/src/main/scala/org/apache/james/task/eventsourcing/WorkerStatusListener.scala
index 1edbf03..721792b 100644
--- a/server/task/task-memory/src/main/scala/org/apache/james/task/eventsourcing/WorkerStatusListener.scala
+++ b/server/task/task-memory/src/main/scala/org/apache/james/task/eventsourcing/WorkerStatusListener.scala
@@ -27,30 +27,29 @@ import org.apache.james.task.Task.Result
 import org.apache.james.task.eventsourcing.TaskCommand._
 import org.apache.james.task.{TaskExecutionDetails, TaskId, TaskManagerWorker}
 import org.reactivestreams.Publisher
-
 import reactor.core.scala.publisher.SMono
 
 import scala.compat.java8.OptionConverters._
 
 case class WorkerStatusListener(eventSourcingSystem: EventSourcingSystem) extends TaskManagerWorker.Listener {
 
-  override def started(taskId: TaskId): Publisher[Void] = eventSourcingSystem.dispatch(Start(taskId))
+  override def started(taskId: TaskId): Publisher[Void] = SMono(eventSourcingSystem.dispatch(Start(taskId))).`then`()
 
   override def completed(taskId: TaskId, result: Result, additionalInformation: Optional[TaskExecutionDetails.AdditionalInformation]): Publisher[Void] =
-    eventSourcingSystem.dispatch(Complete(taskId, result, additionalInformation.asScala))
+    SMono(eventSourcingSystem.dispatch(Complete(taskId, result, additionalInformation.asScala))).`then`()
 
   override def failed(taskId: TaskId, additionalInformation: Optional[TaskExecutionDetails.AdditionalInformation], errorMessage: String, t: Throwable): Publisher[Void] =
-    eventSourcingSystem.dispatch(Fail(taskId, additionalInformation.asScala, Some(errorMessage), Some(Throwables.getStackTraceAsString(t))))
+    SMono(eventSourcingSystem.dispatch(Fail(taskId, additionalInformation.asScala, Some(errorMessage), Some(Throwables.getStackTraceAsString(t))))).`then`()
 
   override def failed(taskId: TaskId, additionalInformation: Optional[TaskExecutionDetails.AdditionalInformation], t: Throwable): Publisher[Void] =
-    eventSourcingSystem.dispatch(Fail(taskId, additionalInformation.asScala, None, Some(Throwables.getStackTraceAsString(t))))
+    SMono(eventSourcingSystem.dispatch(Fail(taskId, additionalInformation.asScala, None, Some(Throwables.getStackTraceAsString(t))))).`then`()
 
   override def failed(taskId: TaskId, additionalInformation: Optional[TaskExecutionDetails.AdditionalInformation]): Publisher[Void] =
-    eventSourcingSystem.dispatch(Fail(taskId, additionalInformation.asScala, None, None))
+    SMono(eventSourcingSystem.dispatch(Fail(taskId, additionalInformation.asScala, None, None))).`then`()
 
   override def cancelled(taskId: TaskId, additionalInformation: Optional[TaskExecutionDetails.AdditionalInformation]): Publisher[Void] =
-    eventSourcingSystem.dispatch(Cancel(taskId, additionalInformation.asScala ))
+    SMono(eventSourcingSystem.dispatch(Cancel(taskId, additionalInformation.asScala ))).`then`()
 
   override def updated(taskId: TaskId, additionalInformation: TaskExecutionDetails.AdditionalInformation): Publisher[Void] =
-    eventSourcingSystem.dispatch(UpdateAdditionalInformation(taskId, additionalInformation))
+    SMono(eventSourcingSystem.dispatch(UpdateAdditionalInformation(taskId, additionalInformation))).`then`()
 }
\ No newline at end of file


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


[james-project] 09/13: JAMES-3435 Merge ACLReseted and ACLUpdated events

Posted by bt...@apache.org.
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 fa3db02bbde84cfa4774890ea2c74d2b05471269
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sat Dec 5 08:54:36 2020 +0700

    JAMES-3435 Merge ACLReseted and ACLUpdated events
    
    Less code, but also shipping commands in events sounds
    like an eventSourcing anti-pattern...
---
 .../java/org/apache/james/mailbox/acl/ACLDiff.java |  16 +++
 .../mailbox/cassandra/mail/CassandraACLDAOV2.java  |  21 ----
 .../mailbox/cassandra/mail/CassandraACLMapper.java |   7 +-
 .../mail/eventsourcing/acl/ACLCommandDTO.java      |  94 ------------------
 .../mail/eventsourcing/acl/ACLModule.java          |   9 --
 .../mail/eventsourcing/acl/ACLReseted.java         |  75 ---------------
 .../mail/eventsourcing/acl/ACLResetedDTO.java      | 107 ---------------------
 .../mail/eventsourcing/acl/ACLUpdated.java         |  12 +--
 .../mail/eventsourcing/acl/ACLUpdatedDTO.java      |  16 +--
 .../mail/eventsourcing/acl/AclV2DAOSubscriber.java |  15 +--
 .../eventsourcing/acl/MailboxACLAggregate.java     |  15 +--
 .../eventsourcing/acl/UserRightsDAOSubscriber.java |   5 -
 .../cassandra/CassandraMailboxManagerTest.java     |   2 +-
 .../cassandra/mail/CassandraACLMapperV1Test.java   |   2 +-
 .../cassandra/mail/CassandraACLMapperV2Test.java   |   6 +-
 .../cassandra/mail/CassandraMailboxMapperTest.java |   2 +-
 .../mail/CassandraMailboxMapperV10Test.java        |   2 +-
 .../mail/migration/AclV2MigrationTest.java         |   2 +-
 .../mail/migration/MailboxPathV2MigrationTest.java |   2 +-
 .../mailbox/cassandra/mail/utils/GuiceUtils.java   |   4 -
 .../modules/mailbox/CassandraMailboxModule.java    |   2 -
 21 files changed, 44 insertions(+), 372 deletions(-)

diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/acl/ACLDiff.java b/mailbox/api/src/main/java/org/apache/james/mailbox/acl/ACLDiff.java
index 7631261..7b5643d 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/acl/ACLDiff.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/acl/ACLDiff.java
@@ -70,6 +70,22 @@ public class ACLDiff {
             && !oldEntries.get(entry.getKey()).equals(entry.getValue());
     }
 
+    public Stream<MailboxACL.ACLCommand> commands() {
+        return Stream.concat(
+            addedEntries()
+                .map(entry -> MailboxACL.command()
+                    .mode(MailboxACL.EditMode.ADD)
+                    .key(entry.getKey())
+                    .rights(entry.getValue())
+                    .build()),
+            removedEntries()
+                .map(entry -> MailboxACL.command()
+                    .mode(MailboxACL.EditMode.REMOVE)
+                    .key(entry.getKey())
+                    .rights(entry.getValue())
+                    .build()));
+    }
+
     public MailboxACL getOldACL() {
         return oldACL;
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
index 8357650..e3a59a6 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLDAOV2.java
@@ -36,7 +36,6 @@ import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
 import org.apache.james.mailbox.cassandra.table.CassandraACLV2Table;
 import org.apache.james.mailbox.model.MailboxACL;
 
-import com.datastax.driver.core.BatchStatement;
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.querybuilder.QueryBuilder;
@@ -45,7 +44,6 @@ import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
-import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraACLDAOV2 {
@@ -124,13 +122,6 @@ public class CassandraACLDAOV2 {
             .reduce(Throwing.biFunction(MailboxACL::union));
     }
 
-    public Mono<Void> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
-        return delete(cassandraId)
-                .then(Flux.fromIterable(mailboxACL.getEntries().entrySet())
-                    .concatMap(entry -> doSetACL(cassandraId, mailboxACL))
-                    .then());
-    }
-
     public Mono<Void> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
         ImmutableSet<String> rightStrings = asStringSet(command.getRights());
         switch (command.getEditMode()) {
@@ -161,16 +152,4 @@ public class CassandraACLDAOV2 {
             .map(String::valueOf)
             .collect(Guavate.toImmutableSet());
     }
-
-    public Mono<Void> doSetACL(CassandraId cassandraId, MailboxACL mailboxACL) {
-        BatchStatement batchStatement = new BatchStatement();
-        mailboxACL.getEntries().entrySet()
-            .stream().map(entry -> replaceRights.bind()
-            .setUUID(CassandraACLV2Table.ID, cassandraId.asUuid())
-            .setString(CassandraACLV2Table.KEY, entry.getKey().serialize())
-            .setSet(CassandraACLV2Table.RIGHTS, asStringSet(entry.getValue()), String.class))
-            .forEach(batchStatement::add);
-
-        return executor.executeVoid(batchStatement);
-    }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
index 116c8fa..e91d2aa 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
@@ -32,7 +32,6 @@ import org.apache.james.eventsourcing.Subscriber;
 import org.apache.james.eventsourcing.eventstore.EventStore;
 import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLReseted;
 import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLUpdated;
 import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.AclV2DAOSubscriber;
 import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.DeleteMailboxCommand;
@@ -133,9 +132,9 @@ public class CassandraACLMapper {
         public Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
             return Mono.from(eventSourcingSystem.dispatch(new SetACLCommand(new MailboxAggregateId(cassandraId), mailboxACL)))
                 .flatMapIterable(events -> events)
-                .filter(ACLReseted.class::isInstance)
-                .map(ACLReseted.class::cast)
-                .map(ACLReseted::getAclDiff)
+                .filter(ACLUpdated.class::isInstance)
+                .map(ACLUpdated.class::cast)
+                .map(ACLUpdated::getAclDiff)
                 .next()
                 .switchIfEmpty(Mono.defer(() -> Mono.error(new MailboxException("Unable to set ACL"))));
         }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLCommandDTO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLCommandDTO.java
deleted file mode 100644
index 16f5e6f..0000000
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLCommandDTO.java
+++ /dev/null
@@ -1,94 +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.mailbox.cassandra.mail.eventsourcing.acl;
-
-import java.util.Objects;
-
-import org.apache.james.mailbox.exception.UnsupportedRightException;
-import org.apache.james.mailbox.model.MailboxACL;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-public class ACLCommandDTO {
-    public static ACLCommandDTO fromCommand(MailboxACL.ACLCommand command) {
-        return new ACLCommandDTO(command.getEditMode().name(),
-            command.getEntryKey().serialize(),
-            command.getRights().serialize());
-    }
-
-    private final String mode;
-    private final String entry;
-    private final String rights;
-
-    @JsonCreator
-    public ACLCommandDTO(@JsonProperty("mode") String mode,
-                         @JsonProperty("entry") String entry,
-                         @JsonProperty("rights") String rights) {
-        this.mode = mode;
-        this.entry = entry;
-        this.rights = rights;
-    }
-
-
-    @JsonProperty("mode")
-    public String getMode() {
-        return mode;
-    }
-
-    @JsonProperty("entry")
-    public String getEntry() {
-        return entry;
-    }
-
-    @JsonProperty("rights")
-    public String getRights() {
-        return rights;
-    }
-
-    public MailboxACL.ACLCommand asACLCommand() {
-        try {
-            return MailboxACL.command()
-                .key(MailboxACL.EntryKey.deserialize(entry))
-                .rights(MailboxACL.Rfc4314Rights.deserialize(rights))
-                .mode(MailboxACL.EditMode.parse(mode).orElseThrow(() -> new IllegalArgumentException(mode + " is not a supported EditMode")))
-                .build();
-        } catch (UnsupportedRightException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof ACLCommandDTO) {
-            ACLCommandDTO that = (ACLCommandDTO) o;
-
-            return Objects.equals(this.mode, that.mode)
-                && Objects.equals(this.entry, that.entry)
-                && Objects.equals(this.rights, that.rights);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(mode, entry, rights);
-    }
-}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLModule.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLModule.java
index 64b72c7..60eaab8 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLModule.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLModule.java
@@ -24,17 +24,8 @@ import org.apache.james.json.DTOModule;
 
 public interface ACLModule {
 
-    String RESET_TYPE_NAME = "acl-reseted";
     String UPDATE_TYPE_NAME = "acl-updated";
 
-    EventDTOModule<ACLReseted, ACLResetedDTO> ACL_RESET =
-        new DTOModule.Builder<>(ACLReseted.class)
-            .convertToDTO(ACLResetedDTO.class)
-            .toDomainObjectConverter(ACLResetedDTO::toEvent)
-            .toDTOConverter(ACLResetedDTO::from)
-            .typeName(RESET_TYPE_NAME)
-            .withFactory(EventDTOModule::new);
-
     EventDTOModule<ACLUpdated, ACLUpdatedDTO> ACL_UPDATE =
         new DTOModule.Builder<>(ACLUpdated.class)
             .convertToDTO(ACLUpdatedDTO.class)
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLReseted.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLReseted.java
deleted file mode 100644
index 33ecadc..0000000
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLReseted.java
+++ /dev/null
@@ -1,75 +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.mailbox.cassandra.mail.eventsourcing.acl;
-
-import java.util.Objects;
-
-import org.apache.james.eventsourcing.AggregateId;
-import org.apache.james.eventsourcing.Event;
-import org.apache.james.eventsourcing.EventId;
-import org.apache.james.mailbox.acl.ACLDiff;
-import org.apache.james.mailbox.cassandra.ids.CassandraId;
-
-public class ACLReseted implements Event {
-    private final MailboxAggregateId id;
-    private final EventId eventId;
-    private final ACLDiff aclDiff;
-
-    public ACLReseted(MailboxAggregateId id, EventId eventId, ACLDiff aclDiff) {
-        this.id = id;
-        this.eventId = eventId;
-        this.aclDiff = aclDiff;
-    }
-
-    public CassandraId mailboxId() {
-        return id.asMailboxId();
-    }
-
-    public ACLDiff getAclDiff() {
-        return aclDiff;
-    }
-
-    @Override
-    public EventId eventId() {
-        return eventId;
-    }
-
-    @Override
-    public AggregateId getAggregateId() {
-        return id;
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof ACLReseted) {
-            ACLReseted that = (ACLReseted) o;
-
-            return Objects.equals(this.eventId, that.eventId)
-                && Objects.equals(this.id, that.id)
-                && Objects.equals(this.aclDiff, that.aclDiff);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(eventId, id, aclDiff);
-    }
-}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLResetedDTO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLResetedDTO.java
deleted file mode 100644
index 354d765..0000000
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLResetedDTO.java
+++ /dev/null
@@ -1,107 +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.mailbox.cassandra.mail.eventsourcing.acl;
-
-import java.util.Objects;
-
-import org.apache.james.eventsourcing.EventId;
-import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTO;
-import org.apache.james.mailbox.cassandra.ids.CassandraId;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Preconditions;
-
-class ACLResetedDTO implements EventDTO {
-
-    static ACLResetedDTO from(ACLReseted event, String type) {
-        Preconditions.checkNotNull(event);
-
-        return new ACLResetedDTO(
-                event.eventId().serialize(),
-                event.getAggregateId().asAggregateKey(),
-                type,
-                ACLDiffDTO.fromACLDiff(event.getAclDiff()));
-    }
-
-    static ACLResetedDTO from(ACLReseted event) {
-        return from(event, ACLModule.RESET_TYPE_NAME);
-    }
-
-    private final int eventId;
-    private final String aggregateKey;
-    private final String type;
-    private final ACLDiffDTO aclDiff;
-
-    @JsonCreator
-    ACLResetedDTO(
-            @JsonProperty("eventId") int eventId,
-            @JsonProperty("aggregateKey") String aggregateKey,
-            @JsonProperty("type") String type,
-            @JsonProperty("aclDiff") ACLDiffDTO aclDiff) {
-        this.eventId = eventId;
-        this.aggregateKey = aggregateKey;
-        this.type = type;
-        this.aclDiff = aclDiff;
-    }
-
-    @JsonIgnore
-    public ACLReseted toEvent() {
-        return new ACLReseted(
-            new MailboxAggregateId(CassandraId.of(aggregateKey)),
-            EventId.fromSerialized(eventId),
-            aclDiff.asACLDiff());
-    }
-
-    public int getEventId() {
-        return eventId;
-    }
-
-    public String getAggregateKey() {
-        return aggregateKey;
-    }
-
-    public String getType() {
-        return type;
-    }
-
-    public ACLDiffDTO getAclDiff() {
-        return aclDiff;
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof ACLResetedDTO) {
-            ACLResetedDTO that = (ACLResetedDTO) o;
-
-            return Objects.equals(this.eventId, that.eventId)
-                && Objects.equals(this.aggregateKey, that.aggregateKey)
-                && Objects.equals(this.type, that.type)
-                && Objects.equals(this.aclDiff, that.aclDiff);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(eventId, aggregateKey, type, aclDiff);
-    }
-}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdated.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdated.java
index 604209c..048b8b7 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdated.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdated.java
@@ -26,18 +26,15 @@ import org.apache.james.eventsourcing.Event;
 import org.apache.james.eventsourcing.EventId;
 import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.model.MailboxACL;
 
 public class ACLUpdated implements Event {
     private final MailboxAggregateId id;
     private final EventId eventId;
-    private final MailboxACL.ACLCommand command;
     private final ACLDiff aclDiff;
 
-    public ACLUpdated(MailboxAggregateId id, EventId eventId, MailboxACL.ACLCommand command, ACLDiff aclDiff) {
+    public ACLUpdated(MailboxAggregateId id, EventId eventId, ACLDiff aclDiff) {
         this.id = id;
         this.eventId = eventId;
-        this.command = command;
         this.aclDiff = aclDiff;
     }
 
@@ -59,10 +56,6 @@ public class ACLUpdated implements Event {
         return aclDiff;
     }
 
-    public MailboxACL.ACLCommand getCommand() {
-        return command;
-    }
-
     @Override
     public final boolean equals(Object o) {
         if (o instanceof ACLUpdated) {
@@ -70,7 +63,6 @@ public class ACLUpdated implements Event {
 
             return Objects.equals(this.eventId, that.eventId)
                 && Objects.equals(this.id, that.id)
-                && Objects.equals(this.command, that.command)
                 && Objects.equals(this.aclDiff, that.aclDiff);
         }
         return false;
@@ -78,6 +70,6 @@ public class ACLUpdated implements Event {
 
     @Override
     public final int hashCode() {
-        return Objects.hash(eventId, id, aclDiff, command);
+        return Objects.hash(eventId, id, aclDiff);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTO.java
index 8870745..a1a3b4f 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTO.java
@@ -39,8 +39,7 @@ class ACLUpdatedDTO implements EventDTO {
                 event.eventId().serialize(),
                 event.getAggregateId().asAggregateKey(),
                 type,
-                ACLDiffDTO.fromACLDiff(event.getAclDiff()),
-                ACLCommandDTO.fromCommand(event.getCommand()));
+                ACLDiffDTO.fromACLDiff(event.getAclDiff()));
     }
 
     static ACLUpdatedDTO from(ACLUpdated event) {
@@ -51,19 +50,16 @@ class ACLUpdatedDTO implements EventDTO {
     private final String aggregateKey;
     private final String type;
     private final ACLDiffDTO aclDiff;
-    private final ACLCommandDTO command;
 
     @JsonCreator
     ACLUpdatedDTO(@JsonProperty("eventId") int eventId,
                   @JsonProperty("aggregateKey") String aggregateKey,
                   @JsonProperty("type") String type,
-                  @JsonProperty("aclDiff") ACLDiffDTO aclDiff,
-                  @JsonProperty("command") ACLCommandDTO command) {
+                  @JsonProperty("aclDiff") ACLDiffDTO aclDiff) {
         this.eventId = eventId;
         this.aggregateKey = aggregateKey;
         this.type = type;
         this.aclDiff = aclDiff;
-        this.command = command;
     }
 
     @JsonIgnore
@@ -71,7 +67,6 @@ class ACLUpdatedDTO implements EventDTO {
         return new ACLUpdated(
             new MailboxAggregateId(CassandraId.of(aggregateKey)),
             EventId.fromSerialized(eventId),
-            command.asACLCommand(),
             aclDiff.asACLDiff());
     }
 
@@ -91,10 +86,6 @@ class ACLUpdatedDTO implements EventDTO {
         return aclDiff;
     }
 
-    public ACLCommandDTO getCommand() {
-        return command;
-    }
-
     @Override
     public final boolean equals(Object o) {
         if (o instanceof ACLUpdatedDTO) {
@@ -103,7 +94,6 @@ class ACLUpdatedDTO implements EventDTO {
             return Objects.equals(this.eventId, that.eventId)
                 && Objects.equals(this.aggregateKey, that.aggregateKey)
                 && Objects.equals(this.type, that.type)
-                && Objects.equals(this.command, that.command)
                 && Objects.equals(this.aclDiff, that.aclDiff);
         }
         return false;
@@ -111,6 +101,6 @@ class ACLUpdatedDTO implements EventDTO {
 
     @Override
     public final int hashCode() {
-        return Objects.hash(eventId, aggregateKey, type, aclDiff, command);
+        return Objects.hash(eventId, aggregateKey, type, aclDiff);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/AclV2DAOSubscriber.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/AclV2DAOSubscriber.java
index be41fa9..6c579ea 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/AclV2DAOSubscriber.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/AclV2DAOSubscriber.java
@@ -23,6 +23,8 @@ import org.apache.james.eventsourcing.Event;
 import org.apache.james.eventsourcing.Subscriber;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV2;
 
+import reactor.core.publisher.Flux;
+
 public class AclV2DAOSubscriber implements Subscriber {
     private final CassandraACLDAOV2 acldaov2;
 
@@ -32,15 +34,14 @@ public class AclV2DAOSubscriber implements Subscriber {
 
     @Override
     public void handle(Event event) {
-        if (event instanceof ACLReseted) {
-            ACLReseted aclReseted = (ACLReseted) event;
-            acldaov2.setACL(aclReseted.mailboxId(), aclReseted.getAclDiff().getNewACL())
-                .block();
-        }
         if (event instanceof ACLUpdated) {
             ACLUpdated aclUpdated = (ACLUpdated) event;
-            acldaov2.updateACL(aclUpdated.mailboxId(), aclUpdated.getCommand())
-                .block();
+
+            Flux.fromStream(
+                aclUpdated.getAclDiff()
+                    .commands())
+                .flatMap(command -> acldaov2.updateACL(aclUpdated.mailboxId(), command))
+                .blockLast();
         }
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxACLAggregate.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxACLAggregate.java
index 485d0d2..79ca0d5 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxACLAggregate.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxACLAggregate.java
@@ -66,32 +66,23 @@ public class MailboxACLAggregate {
     }
 
     public List<Event> deleteMailbox() {
-        return ImmutableList.of(new ACLReseted(aggregateId, history.getNextEventId(),
+        return ImmutableList.of(new ACLUpdated(aggregateId, history.getNextEventId(),
             ACLDiff.computeDiff(state.acl.orElse(MailboxACL.EMPTY), MailboxACL.EMPTY)));
     }
 
     public List<Event> set(SetACLCommand setACLCommand) {
-        return ImmutableList.of(new ACLReseted(aggregateId, history.getNextEventId(),
+        return ImmutableList.of(new ACLUpdated(aggregateId, history.getNextEventId(),
             ACLDiff.computeDiff(state.acl.orElse(MailboxACL.EMPTY), setACLCommand.getAcl())));
     }
 
     public List<Event> update(UpdateACLCommand command) throws UnsupportedRightException {
         MailboxACL oldACL = state.acl.orElse(MailboxACL.EMPTY);
-        return ImmutableList.of(new ACLUpdated(command.getId(), history.getNextEventId(), command.getAclCommand(),
+        return ImmutableList.of(new ACLUpdated(command.getId(), history.getNextEventId(),
             ACLDiff.computeDiff(oldACL,
                 oldACL.apply(command.getAclCommand()))));
     }
 
     private void apply(Event event) {
-        if (event instanceof ACLReseted) {
-            ACLReseted aclReseted = (ACLReseted) event;
-            MailboxACL newACL = aclReseted.getAclDiff().getNewACL();
-            if (newACL.getEntries().isEmpty()) {
-                state = State.initial();
-            } else {
-                state = State.forAcl(newACL);
-            }
-        }
         if (event instanceof ACLUpdated) {
             ACLUpdated aclUpdated = (ACLUpdated) event;
             state = State.forAcl(aclUpdated.getAclDiff().getNewACL());
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UserRightsDAOSubscriber.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UserRightsDAOSubscriber.java
index 3566b6a..4bdfb19 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UserRightsDAOSubscriber.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UserRightsDAOSubscriber.java
@@ -32,11 +32,6 @@ public class UserRightsDAOSubscriber implements Subscriber {
 
     @Override
     public void handle(Event event) {
-        if (event instanceof ACLReseted) {
-            ACLReseted aclReseted = (ACLReseted) event;
-            userRightsDAO.update(aclReseted.mailboxId(), aclReseted.getAclDiff())
-                .block();
-        }
         if (event instanceof ACLUpdated) {
             ACLUpdated aclUpdated = (ACLUpdated) event;
             userRightsDAO.update(aclUpdated.mailboxId(), aclUpdated.getAclDiff())
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 84dd5b1..6dc9026 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
@@ -801,7 +801,7 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandraCluster.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
             CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandraCluster.getConf());
             JsonEventSerializer jsonEventSerializer = JsonEventSerializer
-                .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+                .forModules(ACLModule.ACL_UPDATE)
                 .withoutNestedType();
             CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandraCluster.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
             CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandraCluster.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
index 1d52765..e34e0b0 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
@@ -67,7 +67,7 @@ class CassandraACLMapperV1Test extends CassandraACLMapperContract {
         CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
         CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandra.getConf());
         JsonEventSerializer jsonEventSerializer = JsonEventSerializer
-            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .forModules(ACLModule.ACL_UPDATE)
             .withoutNestedType();
         CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
         CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
index a1367f1..5b2556f 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
@@ -66,7 +66,7 @@ class CassandraACLMapperV2Test extends CassandraACLMapperContract {
         CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
         CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandra.getConf());
         JsonEventSerializer jsonEventSerializer = JsonEventSerializer
-            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .forModules(ACLModule.ACL_UPDATE)
             .withoutNestedType();
         CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
         CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
@@ -88,7 +88,7 @@ class CassandraACLMapperV2Test extends CassandraACLMapperContract {
             .registerScenario(awaitOn(barrier)
                 .thenExecuteNormally()
                 .times(2)
-                .whenQueryStartsWith("SELECT * FROM aclv2 WHERE id=:id;"));
+                .whenQueryStartsWith("SELECT * FROM eventStore WHERE aggregateId=:aggregateId;"));
 
         MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
         MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
@@ -116,7 +116,7 @@ class CassandraACLMapperV2Test extends CassandraACLMapperContract {
             .registerScenario(awaitOn(barrier)
                 .thenExecuteNormally()
                 .times(2)
-                .whenQueryStartsWith("SELECT * FROM aclv2 WHERE id=:id;"));
+                .whenQueryStartsWith("SELECT * FROM eventStore WHERE aggregateId=:aggregateId;"));
 
         MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
         MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
index b2b5caa..7e9fb00 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
@@ -117,7 +117,7 @@ class CassandraMailboxMapperTest {
         CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
         CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandra.getConf());
         JsonEventSerializer jsonEventSerializer = JsonEventSerializer
-            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .forModules(ACLModule.ACL_UPDATE)
             .withoutNestedType();
         CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
         CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperV10Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperV10Test.java
index 6c70f72..a1a644a 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperV10Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperV10Test.java
@@ -117,7 +117,7 @@ class CassandraMailboxMapperV10Test {
         CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
         CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandra.getConf());
         JsonEventSerializer jsonEventSerializer = JsonEventSerializer
-            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .forModules(ACLModule.ACL_UPDATE)
             .withoutNestedType();
         CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
         CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java
index 83c0c97..1a22a87 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java
@@ -79,7 +79,7 @@ class AclV2MigrationTest {
         daoV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
         daoV2 = new CassandraACLDAOV2(cassandra.getConf());
         JsonEventSerializer jsonEventSerializer = JsonEventSerializer
-            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .forModules(ACLModule.ACL_UPDATE)
             .withoutNestedType();
         CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
         CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
index 86baa97..7d0a29a 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
@@ -107,7 +107,7 @@ class MailboxPathV2MigrationTest {
             cassandraCluster.getCassandraConsistenciesConfiguration());
         CassandraACLDAOV2 aclDAOV2 = new CassandraACLDAOV2(cassandra.getConf());
         JsonEventSerializer jsonEventSerializer = JsonEventSerializer
-            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .forModules(ACLModule.ACL_UPDATE)
             .withoutNestedType();
         CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
         CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
index bb2d0c7..1c6481a 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
@@ -38,7 +38,6 @@ import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTOModule;
 import org.apache.james.json.DTO;
 import org.apache.james.json.DTOModule;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
-import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
 import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.model.MessageId;
 
@@ -73,14 +72,11 @@ public class GuiceUtils {
                                         CassandraMessageId.Factory messageIdFactory,
                                         CassandraConfiguration configuration) {
         return Modules.combine(
-            binder -> binder.bind(CassandraACLDAO.class).to(CassandraACLDAOV1.class),
             binder -> binder.bind(MessageId.Factory.class).toInstance(messageIdFactory),
             binder -> binder.bind(BlobId.Factory.class).toInstance(new HashBlobId.Factory()),
             binder -> binder.bind(BlobStore.class).toProvider(() -> CassandraBlobStoreFactory.forTesting(session).passthrough()),
             binder -> binder.bind(Session.class).toInstance(session),
             binder -> Multibinder.newSetBinder(binder, new TypeLiteral<EventDTOModule<? extends Event, ? extends EventDTO>>() {})
-                .addBinding().toInstance(ACLModule.ACL_RESET),
-            binder -> Multibinder.newSetBinder(binder, new TypeLiteral<EventDTOModule<? extends Event, ? extends EventDTO>>() {})
                 .addBinding().toInstance(ACLModule.ACL_UPDATE),
             binder -> binder.bind(new TypeLiteral<Set<DTOModule<?, ? extends DTO>>>() {}).annotatedWith(Names.named(EventNestedTypes.EVENT_NESTED_TYPES_INJECTION_NAME))
                 .toInstance(ImmutableSet.of()),
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
index 23408f1..1ce6a3d 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
@@ -213,8 +213,6 @@ public class CassandraMailboxModule extends AbstractModule {
         bind(MailboxManager.class).annotatedWith(Names.named(MAILBOXMANAGER_NAME)).to(MailboxManager.class);
 
         Multibinder.newSetBinder(binder(), new TypeLiteral<EventDTOModule<? extends Event, ? extends EventDTO>>() {})
-            .addBinding().toInstance(ACLModule.ACL_RESET);
-        Multibinder.newSetBinder(binder(), new TypeLiteral<EventDTOModule<? extends Event, ? extends EventDTO>>() {})
             .addBinding().toInstance(ACLModule.ACL_UPDATE);
     }
     


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


[james-project] 07/13: JAMES-3435 Pilot Cassandra mailbox ACL changes with an event sourcing system

Posted by bt...@apache.org.
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 86a044f938b92d78bac33e6200030b68d6ec3d49
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Dec 4 12:19:08 2020 +0700

    JAMES-3435 Pilot Cassandra mailbox ACL changes with an event sourcing system
    
    Maintains LWT free, efficient projections which enables optimized reads.
    
    Safe, transactional source of truth with event sourcing.
    
    Rebuilding the projections needs to be added in the future.
---
 .../org/apache/james/mailbox/model/MailboxACL.java |   8 +-
 mailbox/cassandra/pom.xml                          |  12 ++
 .../james/mailbox/cassandra/ids/CassandraId.java   |   6 +-
 .../mailbox/cassandra/mail/CassandraACLMapper.java | 153 +++++++++++++++---
 .../mail/eventsourcing/acl/ACLCommandDTO.java      |  94 +++++++++++
 .../cassandra/mail/eventsourcing/acl/ACLDTO.java   |  73 +++++++++
 .../eventsourcing/acl/ACLDiffDTO.java}             |  70 ++++-----
 .../mail/eventsourcing/acl/ACLModule.java          |  45 ++++++
 .../eventsourcing/acl/ACLReseted.java}             |  67 ++++----
 .../mail/eventsourcing/acl/ACLResetedDTO.java      | 107 +++++++++++++
 .../eventsourcing/acl/ACLUpdated.java}             |  75 ++++-----
 .../mail/eventsourcing/acl/ACLUpdatedDTO.java      | 116 ++++++++++++++
 .../mail/eventsourcing/acl/AclV2DAOSubscriber.java |  46 ++++++
 .../eventsourcing/acl/DeleteMailboxCommand.java    |  61 ++++++++
 .../eventsourcing/acl/MailboxACLAggregate.java     | 100 ++++++++++++
 .../eventsourcing/acl/MailboxAggregateId.java}     |  59 ++-----
 .../mail/eventsourcing/acl/SetACLCommand.java      |  68 ++++++++
 .../mail/eventsourcing/acl/UpdateACLCommand.java   |  70 +++++++++
 .../eventsourcing/acl/UserRightsDAOSubscriber.java |  46 ++++++
 .../cassandra/mail/migration/AclV2Migration.java   |  17 +-
 .../cassandra/CassandraMailboxManagerTest.java     |  23 ++-
 .../cassandra/mail/CassandraACLMapperV1Test.java   |  21 ++-
 .../cassandra/mail/CassandraACLMapperV2Test.java   |  21 ++-
 .../mail/CassandraMailboxMapperAclTest.java        |   2 +
 .../cassandra/mail/CassandraMailboxMapperTest.java |  39 +++--
 ...est.java => CassandraMailboxMapperV10Test.java} | 173 ++++-----------------
 .../cassandra/mail/MailboxAggregateModule.java     |  32 ++--
 .../mail/migration/AclV2MigrationTest.java         |  22 ++-
 .../mail/migration/MailboxPathV2MigrationTest.java |  27 +++-
 .../mailbox/cassandra/mail/utils/GuiceUtils.java   |  23 +++
 .../modules/mailbox/CassandraMailboxModule.java    |  12 +-
 31 files changed, 1294 insertions(+), 394 deletions(-)

diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxACL.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxACL.java
index 22b7f8f..fe0d66f 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxACL.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxACL.java
@@ -69,7 +69,13 @@ public class MailboxACL {
      * SETACL command mode.
      */
     public enum EditMode {
-        ADD, REMOVE, REPLACE
+        ADD, REMOVE, REPLACE;
+
+        public static Optional<EditMode> parse(String string) {
+            return Arrays.stream(values())
+                .filter(value -> value.toString().equalsIgnoreCase(string))
+                .findAny();
+        }
     }
 
     public enum NameType {
diff --git a/mailbox/cassandra/pom.xml b/mailbox/cassandra/pom.xml
index c58966f..385f0b6 100644
--- a/mailbox/cassandra/pom.xml
+++ b/mailbox/cassandra/pom.xml
@@ -89,6 +89,18 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>event-sourcing-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>event-sourcing-event-store-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>event-sourcing-event-store-cassandra</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-json</artifactId>
             <type>test-jar</type>
             <scope>test</scope>
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
index 8de229c..6b5ff6e 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
@@ -32,7 +32,7 @@ public class CassandraId implements MailboxId, Serializable {
     public static class Factory implements MailboxId.Factory {
         @Override
         public CassandraId fromString(String serialized) {
-            return of(UUID.fromString(serialized));
+            return of(serialized);
         }
     }
     
@@ -46,6 +46,10 @@ public class CassandraId implements MailboxId, Serializable {
         return new CassandraId(id);
     }
 
+    public static CassandraId of(String serialized) {
+        return new CassandraId(UUID.fromString(serialized));
+    }
+
     private CassandraId(UUID id) {
         this.id = id;
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
index 517256e..116c8fa 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
@@ -19,66 +19,169 @@
 
 package org.apache.james.mailbox.cassandra.mail;
 
+import java.util.Set;
+
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.backends.cassandra.versions.SchemaVersion;
+import org.apache.james.eventsourcing.Command;
+import org.apache.james.eventsourcing.CommandHandler;
+import org.apache.james.eventsourcing.EventSourcingSystem;
+import org.apache.james.eventsourcing.Subscriber;
+import org.apache.james.eventsourcing.eventstore.EventStore;
 import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLReseted;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLUpdated;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.AclV2DAOSubscriber;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.DeleteMailboxCommand;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.MailboxAggregateId;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.SetACLCommand;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.UpdateACLCommand;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.UserRightsDAOSubscriber;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MailboxACL;
 
+import com.google.common.collect.ImmutableSet;
+
 import reactor.core.publisher.Mono;
 
 public class CassandraACLMapper {
+    public interface Store {
+        Mono<MailboxACL> getACL(CassandraId cassandraId);
+
+        Mono<ACLDiff> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command);
+
+        Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL);
+
+        Mono<Void> delete(CassandraId cassandraId);
+    }
+
+    public static class StoreV1 implements Store {
+        private final CassandraUserMailboxRightsDAO userMailboxRightsDAO;
+        private final CassandraACLDAOV1 cassandraACLDAOV1;
+
+        @Inject
+        public StoreV1(CassandraUserMailboxRightsDAO userMailboxRightsDAO, CassandraACLDAOV1 cassandraACLDAOV1) {
+            this.userMailboxRightsDAO = userMailboxRightsDAO;
+            this.cassandraACLDAOV1 = cassandraACLDAOV1;
+        }
+
+        @Override
+        public Mono<MailboxACL> getACL(CassandraId cassandraId) {
+            return cassandraACLDAOV1.getACL(cassandraId);
+        }
+
+        @Override
+        public Mono<ACLDiff> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
+            return cassandraACLDAOV1.updateACL(cassandraId, command)
+                .flatMap(aclDiff -> userMailboxRightsDAO.update(cassandraId, aclDiff)
+                    .thenReturn(aclDiff))
+                .switchIfEmpty(Mono.error(new MailboxException("Unable to update ACL")));
+        }
+
+        @Override
+        public Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
+            return cassandraACLDAOV1.setACL(cassandraId, mailboxACL)
+                .flatMap(aclDiff -> userMailboxRightsDAO.update(cassandraId, aclDiff)
+                    .thenReturn(aclDiff))
+                .switchIfEmpty(Mono.defer(() -> Mono.error(new MailboxException("Unable to update ACL"))));
+        }
+
+        public Mono<Void> delete(CassandraId cassandraId) {
+            return cassandraACLDAOV1.getACL(cassandraId)
+                .flatMap(acl -> userMailboxRightsDAO.update(cassandraId, ACLDiff.computeDiff(acl, MailboxACL.EMPTY))
+                    .then(cassandraACLDAOV1.delete(cassandraId)));
+        }
+    }
+
+    public static class StoreV2 implements Store {
+        private final CassandraACLDAOV2 cassandraACLDAOV2;
+        private final EventSourcingSystem eventSourcingSystem;
+
+        @Inject
+        public StoreV2(CassandraUserMailboxRightsDAO userMailboxRightsDAO,
+                CassandraACLDAOV2 cassandraACLDAOV2,
+                EventStore eventStore) {
+            this.cassandraACLDAOV2 = cassandraACLDAOV2;
+            Set<CommandHandler<? extends Command>> commandHandlers = ImmutableSet.of(new DeleteMailboxCommand.CommandHandler(eventStore),
+                new UpdateACLCommand.CommandHandler(eventStore),
+                new SetACLCommand.CommandHandler(eventStore));
+            Set<Subscriber> subscribers = ImmutableSet.of(new UserRightsDAOSubscriber(userMailboxRightsDAO),
+                new AclV2DAOSubscriber(cassandraACLDAOV2));
+            eventSourcingSystem = EventSourcingSystem.fromJava(commandHandlers, subscribers, eventStore);
+        }
+
+        @Override
+        public Mono<MailboxACL> getACL(CassandraId cassandraId) {
+            return cassandraACLDAOV2.getACL(cassandraId);
+        }
+
+        @Override
+        public Mono<ACLDiff> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
+            return Mono.from(eventSourcingSystem.dispatch(new UpdateACLCommand(new MailboxAggregateId(cassandraId), command)))
+                .flatMapIterable(events -> events)
+                .filter(ACLUpdated.class::isInstance)
+                .map(ACLUpdated.class::cast)
+                .map(ACLUpdated::getAclDiff)
+                .next()
+                .switchIfEmpty(Mono.defer(() -> Mono.error(new MailboxException("Unable to update ACL"))));
+        }
+
+        @Override
+        public Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
+            return Mono.from(eventSourcingSystem.dispatch(new SetACLCommand(new MailboxAggregateId(cassandraId), mailboxACL)))
+                .flatMapIterable(events -> events)
+                .filter(ACLReseted.class::isInstance)
+                .map(ACLReseted.class::cast)
+                .map(ACLReseted::getAclDiff)
+                .next()
+                .switchIfEmpty(Mono.defer(() -> Mono.error(new MailboxException("Unable to set ACL"))));
+        }
+
+        @Override
+        public Mono<Void> delete(CassandraId cassandraId) {
+            return Mono.from(eventSourcingSystem.dispatch(new DeleteMailboxCommand(new MailboxAggregateId(cassandraId)))).then();
+        }
+    }
+
     public static final SchemaVersion ACL_V2_SCHEME_VERSION = new SchemaVersion(10);
-    private final CassandraUserMailboxRightsDAO userMailboxRightsDAO;
-    private final CassandraACLDAOV1 cassandraACLDAOV1;
-    private final CassandraACLDAOV2 cassandraACLDAOV2;
+    private final StoreV1 storeV1;
+    private final StoreV2 storeV2;
     private final CassandraSchemaVersionManager versionManager;
 
     @Inject
-    public CassandraACLMapper(CassandraUserMailboxRightsDAO userMailboxRightsDAO,
-                              CassandraACLDAOV1 cassandraACLDAOV1,
-                              CassandraACLDAOV2 cassandraACLDAOV2,
-                              CassandraSchemaVersionManager versionManager) {
-        this.cassandraACLDAOV1 = cassandraACLDAOV1;
-        this.cassandraACLDAOV2 = cassandraACLDAOV2;
-        this.userMailboxRightsDAO = userMailboxRightsDAO;
+    public CassandraACLMapper(StoreV1 storeV1, StoreV2 storeV2, CassandraSchemaVersionManager versionManager) {
+        this.storeV1 = storeV1;
+        this.storeV2 = storeV2;
+
         this.versionManager = versionManager;
     }
 
-    private Mono<CassandraACLDAO> aclDao() {
+    private Mono<Store> store() {
         return versionManager.isBefore(ACL_V2_SCHEME_VERSION)
             .map(isBefore -> {
                 if (isBefore) {
-                    return cassandraACLDAOV1;
+                    return storeV1;
                 }
-                return cassandraACLDAOV2;
+                return storeV2;
             });
     }
 
     public Mono<MailboxACL> getACL(CassandraId cassandraId) {
-        return aclDao().flatMap(dao -> dao.getACL(cassandraId));
+        return store().flatMap(store -> store.getACL(cassandraId));
     }
 
     public Mono<ACLDiff> updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) {
-        return aclDao().flatMap(dao -> dao.updateACL(cassandraId, command)
-            .flatMap(aclDiff -> userMailboxRightsDAO.update(cassandraId, aclDiff)
-            .thenReturn(aclDiff))
-            .switchIfEmpty(Mono.error(new MailboxException("Unable to update ACL"))));
+        return store().flatMap(store -> store.updateACL(cassandraId, command));
     }
 
     public Mono<ACLDiff> setACL(CassandraId cassandraId, MailboxACL mailboxACL) {
-        return aclDao().flatMap(dao -> dao.setACL(cassandraId, mailboxACL)
-            .flatMap(aclDiff -> userMailboxRightsDAO.update(cassandraId, aclDiff)
-            .thenReturn(aclDiff))
-            .switchIfEmpty(Mono.defer(() -> Mono.error(new MailboxException("Unable to update ACL")))));
+        return store().flatMap(store -> store.setACL(cassandraId, mailboxACL));
     }
 
     public Mono<Void> delete(CassandraId cassandraId) {
-        return aclDao().flatMap(dao -> dao.getACL(cassandraId)
-            .flatMap(acl -> userMailboxRightsDAO.update(cassandraId, ACLDiff.computeDiff(acl, MailboxACL.EMPTY))
-            .then(dao.delete(cassandraId))));
+        return store().flatMap(store -> store.delete(cassandraId));
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLCommandDTO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLCommandDTO.java
new file mode 100644
index 0000000..16f5e6f
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLCommandDTO.java
@@ -0,0 +1,94 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import java.util.Objects;
+
+import org.apache.james.mailbox.exception.UnsupportedRightException;
+import org.apache.james.mailbox.model.MailboxACL;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ACLCommandDTO {
+    public static ACLCommandDTO fromCommand(MailboxACL.ACLCommand command) {
+        return new ACLCommandDTO(command.getEditMode().name(),
+            command.getEntryKey().serialize(),
+            command.getRights().serialize());
+    }
+
+    private final String mode;
+    private final String entry;
+    private final String rights;
+
+    @JsonCreator
+    public ACLCommandDTO(@JsonProperty("mode") String mode,
+                         @JsonProperty("entry") String entry,
+                         @JsonProperty("rights") String rights) {
+        this.mode = mode;
+        this.entry = entry;
+        this.rights = rights;
+    }
+
+
+    @JsonProperty("mode")
+    public String getMode() {
+        return mode;
+    }
+
+    @JsonProperty("entry")
+    public String getEntry() {
+        return entry;
+    }
+
+    @JsonProperty("rights")
+    public String getRights() {
+        return rights;
+    }
+
+    public MailboxACL.ACLCommand asACLCommand() {
+        try {
+            return MailboxACL.command()
+                .key(MailboxACL.EntryKey.deserialize(entry))
+                .rights(MailboxACL.Rfc4314Rights.deserialize(rights))
+                .mode(MailboxACL.EditMode.parse(mode).orElseThrow(() -> new IllegalArgumentException(mode + " is not a supported EditMode")))
+                .build();
+        } catch (UnsupportedRightException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof ACLCommandDTO) {
+            ACLCommandDTO that = (ACLCommandDTO) o;
+
+            return Objects.equals(this.mode, that.mode)
+                && Objects.equals(this.entry, that.entry)
+                && Objects.equals(this.rights, that.rights);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(mode, entry, rights);
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLDTO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLDTO.java
new file mode 100644
index 0000000..08dd711
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLDTO.java
@@ -0,0 +1,73 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.mailbox.model.MailboxACL;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
+
+public class ACLDTO {
+    public static ACLDTO fromACL(MailboxACL acl) {
+        return new ACLDTO(acl.getEntries().entrySet().stream()
+            .map(entry -> Pair.of(entry.getKey().serialize(), entry.getValue().serialize()))
+            .collect(Guavate.toImmutableMap(Pair::getKey, Pair::getValue)));
+    }
+
+    private final Map<String, String> entries;
+
+    @JsonCreator
+    public ACLDTO(@JsonProperty("entries") Map<String, String> entries) {
+        this.entries = entries;
+    }
+
+    @JsonProperty("entries")
+    public Map<String, String> getEntries() {
+        return entries;
+    }
+
+    public MailboxACL asACL() {
+        return new MailboxACL(entries.entrySet().stream()
+            .map(Throwing.function(entry -> Pair.of(MailboxACL.EntryKey.deserialize(entry.getKey()),
+                MailboxACL.Rfc4314Rights.deserialize(entry.getValue()))))
+            .collect(Guavate.toImmutableMap(Pair::getKey, Pair::getValue)));
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof ACLDTO) {
+            ACLDTO that = (ACLDTO) o;
+
+            return Objects.equals(this.entries, that.entries);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(entries);
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLDiffDTO.java
similarity index 53%
copy from mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
copy to mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLDiffDTO.java
index 8de229c..9b72e1d 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLDiffDTO.java
@@ -16,67 +16,61 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.mailbox.cassandra.ids;
 
-import java.io.Serializable;
-import java.util.Objects;
-import java.util.UUID;
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
 
-import org.apache.james.mailbox.model.MailboxId;
+import java.util.Objects;
 
-import com.datastax.driver.core.utils.UUIDs;
-import com.google.common.base.MoreObjects;
+import org.apache.james.mailbox.acl.ACLDiff;
 
-public class CassandraId implements MailboxId, Serializable {
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
 
-    public static class Factory implements MailboxId.Factory {
-        @Override
-        public CassandraId fromString(String serialized) {
-            return of(UUID.fromString(serialized));
-        }
+public class ACLDiffDTO {
+    public static ACLDiffDTO fromACLDiff(ACLDiff aclDiff) {
+        return new ACLDiffDTO(ACLDTO.fromACL(aclDiff.getOldACL()),
+            ACLDTO.fromACL(aclDiff.getNewACL()));
     }
-    
-    private final UUID id;
 
-    public static CassandraId timeBased() {
-        return of(UUIDs.timeBased());
-    }
+    private final ACLDTO oldAcl;
+    private final ACLDTO newAcl;
 
-    public static CassandraId of(UUID id) {
-        return new CassandraId(id);
+    @JsonCreator
+    public ACLDiffDTO(@JsonProperty("oldAcl") ACLDTO oldAcl,
+                      @JsonProperty("newAcl") ACLDTO newAcl) {
+        this.oldAcl = oldAcl;
+        this.newAcl = newAcl;
     }
 
-    private CassandraId(UUID id) {
-        this.id = id;
+    @JsonProperty("oldAcl")
+    public ACLDTO getOldAcl() {
+        return oldAcl;
     }
 
-    @Override
-    public String serialize() {
-        return id.toString();
+    @JsonProperty("newAcl")
+    public ACLDTO getNewAcl() {
+        return newAcl;
     }
 
-    public UUID asUuid() {
-        return id;
+    public ACLDiff asACLDiff() {
+        return ACLDiff.computeDiff(
+            oldAcl.asACL(),
+            newAcl.asACL());
     }
 
     @Override
     public final boolean equals(Object o) {
-        if (o instanceof CassandraId) {
-            CassandraId other = (CassandraId) o;
-            return Objects.equals(id, other.id);
+        if (o instanceof ACLDiffDTO) {
+            ACLDiffDTO that = (ACLDiffDTO) o;
+
+            return Objects.equals(this.newAcl, that.newAcl)
+                && Objects.equals(this.oldAcl, that.oldAcl);
         }
         return false;
     }
 
     @Override
     public final int hashCode() {
-        return Objects.hash(id);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this)
-            .add("id", id)
-            .toString();
+        return Objects.hash(newAcl, oldAcl);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLModule.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLModule.java
new file mode 100644
index 0000000..64b72c7
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLModule.java
@@ -0,0 +1,45 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTOModule;
+import org.apache.james.json.DTOModule;
+
+public interface ACLModule {
+
+    String RESET_TYPE_NAME = "acl-reseted";
+    String UPDATE_TYPE_NAME = "acl-updated";
+
+    EventDTOModule<ACLReseted, ACLResetedDTO> ACL_RESET =
+        new DTOModule.Builder<>(ACLReseted.class)
+            .convertToDTO(ACLResetedDTO.class)
+            .toDomainObjectConverter(ACLResetedDTO::toEvent)
+            .toDTOConverter(ACLResetedDTO::from)
+            .typeName(RESET_TYPE_NAME)
+            .withFactory(EventDTOModule::new);
+
+    EventDTOModule<ACLUpdated, ACLUpdatedDTO> ACL_UPDATE =
+        new DTOModule.Builder<>(ACLUpdated.class)
+            .convertToDTO(ACLUpdatedDTO.class)
+            .toDomainObjectConverter(ACLUpdatedDTO::toEvent)
+            .toDTOConverter(ACLUpdatedDTO::from)
+            .typeName(UPDATE_TYPE_NAME)
+            .withFactory(EventDTOModule::new);
+}
\ No newline at end of file
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLReseted.java
similarity index 56%
copy from mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
copy to mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLReseted.java
index 8de229c..33ecadc 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLReseted.java
@@ -16,67 +16,60 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.mailbox.cassandra.ids;
 
-import java.io.Serializable;
-import java.util.Objects;
-import java.util.UUID;
-
-import org.apache.james.mailbox.model.MailboxId;
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
 
-import com.datastax.driver.core.utils.UUIDs;
-import com.google.common.base.MoreObjects;
+import java.util.Objects;
 
-public class CassandraId implements MailboxId, Serializable {
+import org.apache.james.eventsourcing.AggregateId;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.EventId;
+import org.apache.james.mailbox.acl.ACLDiff;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
 
-    public static class Factory implements MailboxId.Factory {
-        @Override
-        public CassandraId fromString(String serialized) {
-            return of(UUID.fromString(serialized));
-        }
-    }
-    
-    private final UUID id;
+public class ACLReseted implements Event {
+    private final MailboxAggregateId id;
+    private final EventId eventId;
+    private final ACLDiff aclDiff;
 
-    public static CassandraId timeBased() {
-        return of(UUIDs.timeBased());
+    public ACLReseted(MailboxAggregateId id, EventId eventId, ACLDiff aclDiff) {
+        this.id = id;
+        this.eventId = eventId;
+        this.aclDiff = aclDiff;
     }
 
-    public static CassandraId of(UUID id) {
-        return new CassandraId(id);
+    public CassandraId mailboxId() {
+        return id.asMailboxId();
     }
 
-    private CassandraId(UUID id) {
-        this.id = id;
+    public ACLDiff getAclDiff() {
+        return aclDiff;
     }
 
     @Override
-    public String serialize() {
-        return id.toString();
+    public EventId eventId() {
+        return eventId;
     }
 
-    public UUID asUuid() {
+    @Override
+    public AggregateId getAggregateId() {
         return id;
     }
 
     @Override
     public final boolean equals(Object o) {
-        if (o instanceof CassandraId) {
-            CassandraId other = (CassandraId) o;
-            return Objects.equals(id, other.id);
+        if (o instanceof ACLReseted) {
+            ACLReseted that = (ACLReseted) o;
+
+            return Objects.equals(this.eventId, that.eventId)
+                && Objects.equals(this.id, that.id)
+                && Objects.equals(this.aclDiff, that.aclDiff);
         }
         return false;
     }
 
     @Override
     public final int hashCode() {
-        return Objects.hash(id);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this)
-            .add("id", id)
-            .toString();
+        return Objects.hash(eventId, id, aclDiff);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLResetedDTO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLResetedDTO.java
new file mode 100644
index 0000000..354d765
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLResetedDTO.java
@@ -0,0 +1,107 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ * http://www.apache.org/licenses/LICENSE-2.0                   *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ***************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import java.util.Objects;
+
+import org.apache.james.eventsourcing.EventId;
+import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTO;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Preconditions;
+
+class ACLResetedDTO implements EventDTO {
+
+    static ACLResetedDTO from(ACLReseted event, String type) {
+        Preconditions.checkNotNull(event);
+
+        return new ACLResetedDTO(
+                event.eventId().serialize(),
+                event.getAggregateId().asAggregateKey(),
+                type,
+                ACLDiffDTO.fromACLDiff(event.getAclDiff()));
+    }
+
+    static ACLResetedDTO from(ACLReseted event) {
+        return from(event, ACLModule.RESET_TYPE_NAME);
+    }
+
+    private final int eventId;
+    private final String aggregateKey;
+    private final String type;
+    private final ACLDiffDTO aclDiff;
+
+    @JsonCreator
+    ACLResetedDTO(
+            @JsonProperty("eventId") int eventId,
+            @JsonProperty("aggregateKey") String aggregateKey,
+            @JsonProperty("type") String type,
+            @JsonProperty("aclDiff") ACLDiffDTO aclDiff) {
+        this.eventId = eventId;
+        this.aggregateKey = aggregateKey;
+        this.type = type;
+        this.aclDiff = aclDiff;
+    }
+
+    @JsonIgnore
+    public ACLReseted toEvent() {
+        return new ACLReseted(
+            new MailboxAggregateId(CassandraId.of(aggregateKey)),
+            EventId.fromSerialized(eventId),
+            aclDiff.asACLDiff());
+    }
+
+    public int getEventId() {
+        return eventId;
+    }
+
+    public String getAggregateKey() {
+        return aggregateKey;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public ACLDiffDTO getAclDiff() {
+        return aclDiff;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof ACLResetedDTO) {
+            ACLResetedDTO that = (ACLResetedDTO) o;
+
+            return Objects.equals(this.eventId, that.eventId)
+                && Objects.equals(this.aggregateKey, that.aggregateKey)
+                && Objects.equals(this.type, that.type)
+                && Objects.equals(this.aclDiff, that.aclDiff);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(eventId, aggregateKey, type, aclDiff);
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdated.java
similarity index 50%
copy from mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
copy to mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdated.java
index 8de229c..604209c 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdated.java
@@ -16,67 +16,68 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.mailbox.cassandra.ids;
 
-import java.io.Serializable;
-import java.util.Objects;
-import java.util.UUID;
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
 
-import org.apache.james.mailbox.model.MailboxId;
+import java.util.Objects;
 
-import com.datastax.driver.core.utils.UUIDs;
-import com.google.common.base.MoreObjects;
+import org.apache.james.eventsourcing.AggregateId;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.EventId;
+import org.apache.james.mailbox.acl.ACLDiff;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.model.MailboxACL;
 
-public class CassandraId implements MailboxId, Serializable {
+public class ACLUpdated implements Event {
+    private final MailboxAggregateId id;
+    private final EventId eventId;
+    private final MailboxACL.ACLCommand command;
+    private final ACLDiff aclDiff;
 
-    public static class Factory implements MailboxId.Factory {
-        @Override
-        public CassandraId fromString(String serialized) {
-            return of(UUID.fromString(serialized));
-        }
+    public ACLUpdated(MailboxAggregateId id, EventId eventId, MailboxACL.ACLCommand command, ACLDiff aclDiff) {
+        this.id = id;
+        this.eventId = eventId;
+        this.command = command;
+        this.aclDiff = aclDiff;
     }
-    
-    private final UUID id;
 
-    public static CassandraId timeBased() {
-        return of(UUIDs.timeBased());
+    public CassandraId mailboxId() {
+        return id.asMailboxId();
     }
 
-    public static CassandraId of(UUID id) {
-        return new CassandraId(id);
+    @Override
+    public EventId eventId() {
+        return eventId;
     }
 
-    private CassandraId(UUID id) {
-        this.id = id;
+    @Override
+    public AggregateId getAggregateId() {
+        return id;
     }
 
-    @Override
-    public String serialize() {
-        return id.toString();
+    public ACLDiff getAclDiff() {
+        return aclDiff;
     }
 
-    public UUID asUuid() {
-        return id;
+    public MailboxACL.ACLCommand getCommand() {
+        return command;
     }
 
     @Override
     public final boolean equals(Object o) {
-        if (o instanceof CassandraId) {
-            CassandraId other = (CassandraId) o;
-            return Objects.equals(id, other.id);
+        if (o instanceof ACLUpdated) {
+            ACLUpdated that = (ACLUpdated) o;
+
+            return Objects.equals(this.eventId, that.eventId)
+                && Objects.equals(this.id, that.id)
+                && Objects.equals(this.command, that.command)
+                && Objects.equals(this.aclDiff, that.aclDiff);
         }
         return false;
     }
 
     @Override
     public final int hashCode() {
-        return Objects.hash(id);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this)
-            .add("id", id)
-            .toString();
+        return Objects.hash(eventId, id, aclDiff, command);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTO.java
new file mode 100644
index 0000000..8870745
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/ACLUpdatedDTO.java
@@ -0,0 +1,116 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ * http://www.apache.org/licenses/LICENSE-2.0                   *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ***************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import java.util.Objects;
+
+import org.apache.james.eventsourcing.EventId;
+import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTO;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Preconditions;
+
+class ACLUpdatedDTO implements EventDTO {
+
+    static ACLUpdatedDTO from(ACLUpdated event, String type) {
+        Preconditions.checkNotNull(event);
+
+        return new ACLUpdatedDTO(
+                event.eventId().serialize(),
+                event.getAggregateId().asAggregateKey(),
+                type,
+                ACLDiffDTO.fromACLDiff(event.getAclDiff()),
+                ACLCommandDTO.fromCommand(event.getCommand()));
+    }
+
+    static ACLUpdatedDTO from(ACLUpdated event) {
+        return from(event, ACLModule.UPDATE_TYPE_NAME);
+    }
+
+    private final int eventId;
+    private final String aggregateKey;
+    private final String type;
+    private final ACLDiffDTO aclDiff;
+    private final ACLCommandDTO command;
+
+    @JsonCreator
+    ACLUpdatedDTO(@JsonProperty("eventId") int eventId,
+                  @JsonProperty("aggregateKey") String aggregateKey,
+                  @JsonProperty("type") String type,
+                  @JsonProperty("aclDiff") ACLDiffDTO aclDiff,
+                  @JsonProperty("command") ACLCommandDTO command) {
+        this.eventId = eventId;
+        this.aggregateKey = aggregateKey;
+        this.type = type;
+        this.aclDiff = aclDiff;
+        this.command = command;
+    }
+
+    @JsonIgnore
+    public ACLUpdated toEvent() {
+        return new ACLUpdated(
+            new MailboxAggregateId(CassandraId.of(aggregateKey)),
+            EventId.fromSerialized(eventId),
+            command.asACLCommand(),
+            aclDiff.asACLDiff());
+    }
+
+    public int getEventId() {
+        return eventId;
+    }
+
+    public String getAggregateKey() {
+        return aggregateKey;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public ACLDiffDTO getAclDiff() {
+        return aclDiff;
+    }
+
+    public ACLCommandDTO getCommand() {
+        return command;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof ACLUpdatedDTO) {
+            ACLUpdatedDTO that = (ACLUpdatedDTO) o;
+
+            return Objects.equals(this.eventId, that.eventId)
+                && Objects.equals(this.aggregateKey, that.aggregateKey)
+                && Objects.equals(this.type, that.type)
+                && Objects.equals(this.command, that.command)
+                && Objects.equals(this.aclDiff, that.aclDiff);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(eventId, aggregateKey, type, aclDiff, command);
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/AclV2DAOSubscriber.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/AclV2DAOSubscriber.java
new file mode 100644
index 0000000..be41fa9
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/AclV2DAOSubscriber.java
@@ -0,0 +1,46 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.Subscriber;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV2;
+
+public class AclV2DAOSubscriber implements Subscriber {
+    private final CassandraACLDAOV2 acldaov2;
+
+    public AclV2DAOSubscriber(CassandraACLDAOV2 acldaov2) {
+        this.acldaov2 = acldaov2;
+    }
+
+    @Override
+    public void handle(Event event) {
+        if (event instanceof ACLReseted) {
+            ACLReseted aclReseted = (ACLReseted) event;
+            acldaov2.setACL(aclReseted.mailboxId(), aclReseted.getAclDiff().getNewACL())
+                .block();
+        }
+        if (event instanceof ACLUpdated) {
+            ACLUpdated aclUpdated = (ACLUpdated) event;
+            acldaov2.updateACL(aclUpdated.mailboxId(), aclUpdated.getCommand())
+                .block();
+        }
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/DeleteMailboxCommand.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/DeleteMailboxCommand.java
new file mode 100644
index 0000000..958a86e
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/DeleteMailboxCommand.java
@@ -0,0 +1,61 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import java.util.List;
+
+import org.apache.james.eventsourcing.Command;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+import org.reactivestreams.Publisher;
+
+import reactor.core.publisher.Mono;
+
+public class DeleteMailboxCommand implements Command {
+    public static class CommandHandler implements org.apache.james.eventsourcing.CommandHandler<DeleteMailboxCommand> {
+        private final EventStore eventStore;
+
+        public CommandHandler(EventStore eventStore) {
+            this.eventStore = eventStore;
+        }
+
+        @Override
+        public Class<DeleteMailboxCommand> handledClass() {
+            return DeleteMailboxCommand.class;
+        }
+
+        @Override
+        public Publisher<List<? extends Event>> handle(DeleteMailboxCommand command) {
+            return Mono.from(eventStore.getEventsOfAggregate(command.getId()))
+                .map(history -> MailboxACLAggregate.load(command.getId(), history))
+                .map(aggregate -> aggregate.deleteMailbox());
+        }
+    }
+
+    private final MailboxAggregateId id;
+
+    public DeleteMailboxCommand(MailboxAggregateId id) {
+        this.id = id;
+    }
+
+    public MailboxAggregateId getId() {
+        return id;
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxACLAggregate.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxACLAggregate.java
new file mode 100644
index 0000000..485d0d2
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxACLAggregate.java
@@ -0,0 +1,100 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.History;
+import org.apache.james.mailbox.acl.ACLDiff;
+import org.apache.james.mailbox.exception.UnsupportedRightException;
+import org.apache.james.mailbox.model.MailboxACL;
+
+import com.google.common.collect.ImmutableList;
+
+public class MailboxACLAggregate {
+
+    private static class State {
+        static State initial() {
+            return new State(Optional.empty());
+        }
+
+        static State forAcl(MailboxACL acl) {
+            return new State(Optional.of(acl));
+        }
+
+        private final Optional<MailboxACL> acl;
+
+        private State(Optional<MailboxACL> acl) {
+            this.acl = acl;
+        }
+    }
+
+    public static MailboxACLAggregate load(MailboxAggregateId aggregateId, History history) {
+        return new MailboxACLAggregate(aggregateId, history);
+    }
+
+    private final MailboxAggregateId aggregateId;
+    private final History history;
+    private State state;
+
+    public MailboxACLAggregate(MailboxAggregateId aggregateId, History history) {
+        this.aggregateId = aggregateId;
+        this.history = history;
+
+        this.state = State.initial();
+        history.getEventsJava()
+            .forEach(this::apply);
+    }
+
+    public List<Event> deleteMailbox() {
+        return ImmutableList.of(new ACLReseted(aggregateId, history.getNextEventId(),
+            ACLDiff.computeDiff(state.acl.orElse(MailboxACL.EMPTY), MailboxACL.EMPTY)));
+    }
+
+    public List<Event> set(SetACLCommand setACLCommand) {
+        return ImmutableList.of(new ACLReseted(aggregateId, history.getNextEventId(),
+            ACLDiff.computeDiff(state.acl.orElse(MailboxACL.EMPTY), setACLCommand.getAcl())));
+    }
+
+    public List<Event> update(UpdateACLCommand command) throws UnsupportedRightException {
+        MailboxACL oldACL = state.acl.orElse(MailboxACL.EMPTY);
+        return ImmutableList.of(new ACLUpdated(command.getId(), history.getNextEventId(), command.getAclCommand(),
+            ACLDiff.computeDiff(oldACL,
+                oldACL.apply(command.getAclCommand()))));
+    }
+
+    private void apply(Event event) {
+        if (event instanceof ACLReseted) {
+            ACLReseted aclReseted = (ACLReseted) event;
+            MailboxACL newACL = aclReseted.getAclDiff().getNewACL();
+            if (newACL.getEntries().isEmpty()) {
+                state = State.initial();
+            } else {
+                state = State.forAcl(newACL);
+            }
+        }
+        if (event instanceof ACLUpdated) {
+            ACLUpdated aclUpdated = (ACLUpdated) event;
+            state = State.forAcl(aclUpdated.getAclDiff().getNewACL());
+        }
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxAggregateId.java
similarity index 53%
copy from mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
copy to mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxAggregateId.java
index 8de229c..067f9bc 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/ids/CassandraId.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/MailboxAggregateId.java
@@ -16,67 +16,42 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-package org.apache.james.mailbox.cassandra.ids;
 
-import java.io.Serializable;
-import java.util.Objects;
-import java.util.UUID;
-
-import org.apache.james.mailbox.model.MailboxId;
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
 
-import com.datastax.driver.core.utils.UUIDs;
-import com.google.common.base.MoreObjects;
+import java.util.Objects;
 
-public class CassandraId implements MailboxId, Serializable {
+import org.apache.james.eventsourcing.AggregateId;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
 
-    public static class Factory implements MailboxId.Factory {
-        @Override
-        public CassandraId fromString(String serialized) {
-            return of(UUID.fromString(serialized));
-        }
-    }
-    
-    private final UUID id;
-
-    public static CassandraId timeBased() {
-        return of(UUIDs.timeBased());
-    }
+public class MailboxAggregateId implements AggregateId {
+    private final CassandraId cassandraId;
 
-    public static CassandraId of(UUID id) {
-        return new CassandraId(id);
+    public MailboxAggregateId(CassandraId cassandraId) {
+        this.cassandraId = cassandraId;
     }
 
-    private CassandraId(UUID id) {
-        this.id = id;
+    public CassandraId asMailboxId() {
+        return cassandraId;
     }
 
     @Override
-    public String serialize() {
-        return id.toString();
-    }
-
-    public UUID asUuid() {
-        return id;
+    public String asAggregateKey() {
+        return cassandraId.serialize();
     }
 
     @Override
     public final boolean equals(Object o) {
-        if (o instanceof CassandraId) {
-            CassandraId other = (CassandraId) o;
-            return Objects.equals(id, other.id);
+        if (o instanceof MailboxAggregateId) {
+            MailboxAggregateId that = (MailboxAggregateId) o;
+
+            return Objects.equals(this.cassandraId, that.cassandraId);
         }
         return false;
     }
 
     @Override
     public final int hashCode() {
-        return Objects.hash(id);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this)
-            .add("id", id)
-            .toString();
+        return Objects.hash(cassandraId);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/SetACLCommand.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/SetACLCommand.java
new file mode 100644
index 0000000..8b797f5
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/SetACLCommand.java
@@ -0,0 +1,68 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import java.util.List;
+
+import org.apache.james.eventsourcing.Command;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.reactivestreams.Publisher;
+
+import reactor.core.publisher.Mono;
+
+public class SetACLCommand implements Command {
+    public static class CommandHandler implements org.apache.james.eventsourcing.CommandHandler<SetACLCommand> {
+        private final EventStore eventStore;
+
+        public CommandHandler(EventStore eventStore) {
+            this.eventStore = eventStore;
+        }
+
+        @Override
+        public Class<SetACLCommand> handledClass() {
+            return SetACLCommand.class;
+        }
+
+        @Override
+        public Publisher<List<? extends Event>> handle(SetACLCommand command) {
+            return Mono.from(eventStore.getEventsOfAggregate(command.getId()))
+                .map(history -> MailboxACLAggregate.load(command.getId(), history))
+                .map(aggregate -> aggregate.set(command));
+        }
+    }
+
+    private final MailboxAggregateId id;
+    private final MailboxACL acl;
+
+    public SetACLCommand(MailboxAggregateId id, MailboxACL acl) {
+        this.id = id;
+        this.acl = acl;
+    }
+
+    public MailboxAggregateId getId() {
+        return id;
+    }
+
+    public MailboxACL getAcl() {
+        return acl;
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UpdateACLCommand.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UpdateACLCommand.java
new file mode 100644
index 0000000..607657f
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UpdateACLCommand.java
@@ -0,0 +1,70 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import java.util.List;
+
+import org.apache.james.eventsourcing.Command;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.reactivestreams.Publisher;
+
+import com.github.fge.lambdas.Throwing;
+
+import reactor.core.publisher.Mono;
+
+public class UpdateACLCommand implements Command {
+    public static class CommandHandler implements org.apache.james.eventsourcing.CommandHandler<UpdateACLCommand> {
+        private final EventStore eventStore;
+
+        public CommandHandler(EventStore eventStore) {
+            this.eventStore = eventStore;
+        }
+
+        @Override
+        public Class<UpdateACLCommand> handledClass() {
+            return UpdateACLCommand.class;
+        }
+
+        @Override
+        public Publisher<List<? extends Event>> handle(UpdateACLCommand command) {
+            return Mono.from(eventStore.getEventsOfAggregate(command.getId()))
+                .map(history -> MailboxACLAggregate.load(command.getId(), history))
+                .map(Throwing.function(aggregate -> aggregate.update(command)));
+        }
+    }
+
+    private final MailboxAggregateId id;
+    private final MailboxACL.ACLCommand aclCommand;
+
+    public UpdateACLCommand(MailboxAggregateId id, MailboxACL.ACLCommand aclCommand) {
+        this.id = id;
+        this.aclCommand = aclCommand;
+    }
+
+    public MailboxAggregateId getId() {
+        return id;
+    }
+
+    public MailboxACL.ACLCommand getAclCommand() {
+        return aclCommand;
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UserRightsDAOSubscriber.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UserRightsDAOSubscriber.java
new file mode 100644
index 0000000..3566b6a
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/eventsourcing/acl/UserRightsDAOSubscriber.java
@@ -0,0 +1,46 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mailbox.cassandra.mail.eventsourcing.acl;
+
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.Subscriber;
+import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
+
+public class UserRightsDAOSubscriber implements Subscriber {
+    private final CassandraUserMailboxRightsDAO userRightsDAO;
+
+    public UserRightsDAOSubscriber(CassandraUserMailboxRightsDAO userRightsDAO) {
+        this.userRightsDAO = userRightsDAO;
+    }
+
+    @Override
+    public void handle(Event event) {
+        if (event instanceof ACLReseted) {
+            ACLReseted aclReseted = (ACLReseted) event;
+            userRightsDAO.update(aclReseted.mailboxId(), aclReseted.getAclDiff())
+                .block();
+        }
+        if (event instanceof ACLUpdated) {
+            ACLUpdated aclUpdated = (ACLUpdated) event;
+            userRightsDAO.update(aclUpdated.mailboxId(), aclUpdated.getAclDiff())
+                .block();
+        }
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2Migration.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2Migration.java
index 9d6c7df..6dc1b1b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2Migration.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2Migration.java
@@ -27,8 +27,7 @@ import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
-import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV2;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraMailboxDAO;
 import org.apache.james.task.Task;
 import org.apache.james.task.TaskExecutionDetails;
@@ -81,14 +80,14 @@ public class AclV2Migration implements Migration {
     public static final TaskType TYPE = TaskType.of("acl-v2-migration");
 
     private final CassandraMailboxDAO mailboxDAO;
-    private final CassandraACLDAOV1 daoV1;
-    private final CassandraACLDAOV2 daoV2;
+    private final CassandraACLMapper.StoreV1 storeV1;
+    private final CassandraACLMapper.StoreV2 storeV2;
 
     @Inject
-    public AclV2Migration(CassandraMailboxDAO mailboxDAO, CassandraACLDAOV1 daoV1, CassandraACLDAOV2 daoV2) {
+    public AclV2Migration(CassandraMailboxDAO mailboxDAO, CassandraACLMapper.StoreV1 storeV1, CassandraACLMapper.StoreV2 storeV2) {
         this.mailboxDAO = mailboxDAO;
-        this.daoV1 = daoV1;
-        this.daoV2 = daoV2;
+        this.storeV1 = storeV1;
+        this.storeV2 = storeV2;
     }
 
     @Override
@@ -96,8 +95,8 @@ public class AclV2Migration implements Migration {
         mailboxDAO.retrieveAllMailboxes()
             .flatMap(mailbox -> {
                 CassandraId id = (CassandraId) mailbox.getMailboxId();
-                return daoV1.getACL(id)
-                    .flatMap(acl -> daoV2.doSetACL(id, acl));
+                return storeV1.getACL(id)
+                    .flatMap(acl -> storeV2.setACL(id, acl));
             }, CONCURRENCY)
             .doOnError(t -> LOGGER.error("Error while performing migration", t))
             .subscribeOn(Schedulers.elastic())
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 f1aa8b2..84dd5b1 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,6 +32,7 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
@@ -39,6 +40,9 @@ import org.apache.james.blob.api.BlobStore;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.cassandra.BlobTables;
 import org.apache.james.core.Username;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStore;
+import org.apache.james.eventsourcing.eventstore.cassandra.EventStoreDao;
+import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
 import org.apache.james.mailbox.MailboxManagerTest;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
@@ -62,6 +66,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.FetchGroup;
@@ -791,13 +796,19 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
         }
 
         private CassandraACLMapper aclMapper(CassandraCluster cassandraCluster) {
+            CassandraSchemaVersionDAO schemaVersionDAO = new CassandraSchemaVersionDAO(cassandraCluster.getConf());
+            CassandraSchemaVersionManager versionManager = new CassandraSchemaVersionManager(schemaVersionDAO);
+            CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandraCluster.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
+            CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandraCluster.getConf());
+            JsonEventSerializer jsonEventSerializer = JsonEventSerializer
+                .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+                .withoutNestedType();
+            CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandraCluster.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+            CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandraCluster.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
             return new CassandraACLMapper(
-                rightsDAO(cassandraCluster),
-                new CassandraACLDAOV1(cassandraCluster.getConf(),
-                    CassandraConfiguration.DEFAULT_CONFIGURATION,
-                    cassandra.getCassandraConsistenciesConfiguration()),
-                new CassandraACLDAOV2(cassandraCluster.getConf()),
-                new CassandraSchemaVersionManager(new CassandraSchemaVersionDAO(cassandraCluster.getConf())));
+                new CassandraACLMapper.StoreV1(usersRightDAO, aclDAOV1),
+                new CassandraACLMapper.StoreV2(usersRightDAO, aclDAOv2, eventStore),
+                versionManager);
         }
 
         private CassandraUserMailboxRightsDAO rightsDAO(CassandraCluster cassandraCluster) {
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
index 7cfa3e5..1d52765 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV1Test.java
@@ -39,6 +39,11 @@ import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.backends.cassandra.versions.SchemaVersion;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStore;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreModule;
+import org.apache.james.eventsourcing.eventstore.cassandra.EventStoreDao;
+import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
 import org.apache.james.mailbox.model.MailboxACL;
@@ -49,7 +54,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 class CassandraACLMapperV1Test extends CassandraACLMapperContract {
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
-        CassandraModule.aggregateModules(CassandraAclModule.MODULE, CassandraSchemaVersionModule.MODULE));
+        CassandraModule.aggregateModules(CassandraAclModule.MODULE, CassandraSchemaVersionModule.MODULE, CassandraEventStoreModule.MODULE()));
 
     private CassandraACLMapper cassandraACLMapper;
 
@@ -59,10 +64,16 @@ class CassandraACLMapperV1Test extends CassandraACLMapperContract {
         schemaVersionDAO.truncateVersion().block();
         schemaVersionDAO.updateVersion(new SchemaVersion(9)).block();
         CassandraSchemaVersionManager versionManager = new CassandraSchemaVersionManager(schemaVersionDAO);
-        cassandraACLMapper =  new CassandraACLMapper(
-            new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-            new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT),
-            new CassandraACLDAOV2(cassandra.getConf()),
+        CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
+        CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandra.getConf());
+        JsonEventSerializer jsonEventSerializer = JsonEventSerializer
+            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .withoutNestedType();
+        CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+        CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
+        cassandraACLMapper = new CassandraACLMapper(
+            new CassandraACLMapper.StoreV1(usersRightDAO, aclDAOV1),
+            new CassandraACLMapper.StoreV2(usersRightDAO, aclDAOv2, eventStore),
             versionManager);
     }
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
index f6f8cef..a1367f1 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperV2Test.java
@@ -38,6 +38,11 @@ import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.backends.cassandra.versions.SchemaVersion;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStore;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreModule;
+import org.apache.james.eventsourcing.eventstore.cassandra.EventStoreDao;
+import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.junit.jupiter.api.BeforeEach;
@@ -47,7 +52,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 class CassandraACLMapperV2Test extends CassandraACLMapperContract {
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(
-        CassandraModule.aggregateModules(CassandraAclModule.MODULE, CassandraSchemaVersionModule.MODULE));
+        CassandraModule.aggregateModules(CassandraAclModule.MODULE, CassandraSchemaVersionModule.MODULE, CassandraEventStoreModule.MODULE()));
 
     private CassandraACLMapper cassandraACLMapper;
 
@@ -58,10 +63,16 @@ class CassandraACLMapperV2Test extends CassandraACLMapperContract {
         schemaVersionDAO.truncateVersion().block();
         schemaVersionDAO.updateVersion(new SchemaVersion(10)).block();
         CassandraSchemaVersionManager versionManager = new CassandraSchemaVersionManager(schemaVersionDAO);
-        cassandraACLMapper =  new CassandraACLMapper(
-            new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-            new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT),
-            new CassandraACLDAOV2(cassandra.getConf()),
+        CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
+        CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandra.getConf());
+        JsonEventSerializer jsonEventSerializer = JsonEventSerializer
+            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .withoutNestedType();
+        CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+        CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
+        cassandraACLMapper = new CassandraACLMapper(
+            new CassandraACLMapper.StoreV1(usersRightDAO, aclDAOV1),
+            new CassandraACLMapper.StoreV2(usersRightDAO, aclDAOv2, eventStore),
             versionManager);
     }
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperAclTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperAclTest.java
index 119b715..245205e 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperAclTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperAclTest.java
@@ -23,6 +23,7 @@ import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.blob.cassandra.CassandraBlobModule;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreModule;
 import org.apache.james.mailbox.cassandra.mail.utils.GuiceUtils;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraMailboxModule;
@@ -33,6 +34,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 class CassandraMailboxMapperAclTest extends MailboxMapperACLTest {
 
     private static final CassandraModule MODULES = CassandraModule.aggregateModules(
+        CassandraEventStoreModule.MODULE(),
         CassandraSchemaVersionModule.MODULE,
         CassandraAclModule.MODULE,
         CassandraMailboxModule.MODULE,
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
index 678dd69..b2b5caa 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
@@ -33,13 +33,19 @@ import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.Scenario;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.apache.james.core.Username;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStore;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreModule;
+import org.apache.james.eventsourcing.eventstore.cassandra.EventStoreDao;
+import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraMailboxModule;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
@@ -78,9 +84,10 @@ class CassandraMailboxMapperTest {
     private static final Mailbox MAILBOX_BIS = new Mailbox(MAILBOX_PATH, UID_VALIDITY, MAILBOX_ID_2);
 
     private static final CassandraModule MODULES = CassandraModule.aggregateModules(
+        CassandraAclModule.MODULE,
+        CassandraEventStoreModule.MODULE(),
         CassandraMailboxModule.MODULE,
-        CassandraSchemaVersionModule.MODULE,
-        CassandraAclModule.MODULE);
+        CassandraSchemaVersionModule.MODULE);
     private static final int TRY_COUNT_BEFORE_FAILURE = 6;
 
     @RegisterExtension
@@ -100,28 +107,32 @@ class CassandraMailboxMapperTest {
         mailboxPathDAO = new CassandraMailboxPathDAOImpl(cassandra.getConf(), cassandra.getTypesProvider(), cassandraCluster.getCassandraConsistenciesConfiguration());
         mailboxPathV2DAO = new CassandraMailboxPathV2DAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION, cassandraCluster.getCassandraConsistenciesConfiguration());
         mailboxPathV3DAO = new CassandraMailboxPathV3DAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION, cassandraCluster.getCassandraConsistenciesConfiguration());
-        CassandraUserMailboxRightsDAO userMailboxRightsDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
-        CassandraACLMapper aclMapper = new CassandraACLMapper(
-            new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-            new CassandraACLDAOV1(cassandra.getConf(),
-                CassandraConfiguration.DEFAULT_CONFIGURATION,
-                cassandraCluster.getCassandraConsistenciesConfiguration()),
-            new CassandraACLDAOV2(cassandra.getConf()),
-            new CassandraSchemaVersionManager(new CassandraSchemaVersionDAO(cassandra.getConf())));
-        versionDAO = new CassandraSchemaVersionDAO(cassandra.getConf());
 
+        versionDAO = new CassandraSchemaVersionDAO(cassandra.getConf());
         versionDAO.truncateVersion()
             .then(versionDAO.updateVersion(new SchemaVersion(7)))
             .block();
-
+        CassandraSchemaVersionManager versionManager = new CassandraSchemaVersionManager(versionDAO);
+
+        CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
+        CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandra.getConf());
+        JsonEventSerializer jsonEventSerializer = JsonEventSerializer
+            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .withoutNestedType();
+        CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+        CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
+        CassandraACLMapper aclMapper = new CassandraACLMapper(
+            new CassandraACLMapper.StoreV1(usersRightDAO, aclDAOV1),
+            new CassandraACLMapper.StoreV2(usersRightDAO, aclDAOv2, eventStore),
+            versionManager);
         testee = new CassandraMailboxMapper(
             mailboxDAO,
             mailboxPathDAO,
             mailboxPathV2DAO,
             mailboxPathV3DAO,
-            userMailboxRightsDAO,
+            usersRightDAO,
             aclMapper,
-            new CassandraSchemaVersionManager(versionDAO),
+            versionManager,
             CassandraConfiguration.DEFAULT_CONFIGURATION);
     }
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperV10Test.java
similarity index 88%
copy from mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
copy to mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperV10Test.java
index 678dd69..6c70f72 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperV10Test.java
@@ -33,13 +33,19 @@ import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.Scenario;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.apache.james.core.Username;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStore;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreModule;
+import org.apache.james.eventsourcing.eventstore.cassandra.EventStoreDao;
+import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraMailboxModule;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
@@ -64,7 +70,7 @@ import com.github.fge.lambdas.runnable.ThrowingRunnable;
 
 import reactor.core.publisher.Mono;
 
-class CassandraMailboxMapperTest {
+class CassandraMailboxMapperV10Test {
     private static final UidValidity UID_VALIDITY = UidValidity.of(52);
     private static final Username USER = Username.of("user");
     private static final CassandraId MAILBOX_ID = CassandraId.timeBased();
@@ -78,9 +84,10 @@ class CassandraMailboxMapperTest {
     private static final Mailbox MAILBOX_BIS = new Mailbox(MAILBOX_PATH, UID_VALIDITY, MAILBOX_ID_2);
 
     private static final CassandraModule MODULES = CassandraModule.aggregateModules(
+        CassandraAclModule.MODULE,
+        CassandraEventStoreModule.MODULE(),
         CassandraMailboxModule.MODULE,
-        CassandraSchemaVersionModule.MODULE,
-        CassandraAclModule.MODULE);
+        CassandraSchemaVersionModule.MODULE);
     private static final int TRY_COUNT_BEFORE_FAILURE = 6;
 
     @RegisterExtension
@@ -100,28 +107,32 @@ class CassandraMailboxMapperTest {
         mailboxPathDAO = new CassandraMailboxPathDAOImpl(cassandra.getConf(), cassandra.getTypesProvider(), cassandraCluster.getCassandraConsistenciesConfiguration());
         mailboxPathV2DAO = new CassandraMailboxPathV2DAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION, cassandraCluster.getCassandraConsistenciesConfiguration());
         mailboxPathV3DAO = new CassandraMailboxPathV3DAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION, cassandraCluster.getCassandraConsistenciesConfiguration());
-        CassandraUserMailboxRightsDAO userMailboxRightsDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
-        CassandraACLMapper aclMapper = new CassandraACLMapper(
-            new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-            new CassandraACLDAOV1(cassandra.getConf(),
-                CassandraConfiguration.DEFAULT_CONFIGURATION,
-                cassandraCluster.getCassandraConsistenciesConfiguration()),
-            new CassandraACLDAOV2(cassandra.getConf()),
-            new CassandraSchemaVersionManager(new CassandraSchemaVersionDAO(cassandra.getConf())));
-        versionDAO = new CassandraSchemaVersionDAO(cassandra.getConf());
 
+        versionDAO = new CassandraSchemaVersionDAO(cassandra.getConf());
         versionDAO.truncateVersion()
-            .then(versionDAO.updateVersion(new SchemaVersion(7)))
+            .then(versionDAO.updateVersion(new SchemaVersion(10)))
             .block();
+        CassandraSchemaVersionManager versionManager = new CassandraSchemaVersionManager(versionDAO);
 
+        CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
+        CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandra.getConf());
+        JsonEventSerializer jsonEventSerializer = JsonEventSerializer
+            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .withoutNestedType();
+        CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+        CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
+        CassandraACLMapper aclMapper = new CassandraACLMapper(
+            new CassandraACLMapper.StoreV1(usersRightDAO, aclDAOV1),
+            new CassandraACLMapper.StoreV2(usersRightDAO, aclDAOv2, eventStore),
+            versionManager);
         testee = new CassandraMailboxMapper(
             mailboxDAO,
             mailboxPathDAO,
             mailboxPathV2DAO,
             mailboxPathV3DAO,
-            userMailboxRightsDAO,
+            usersRightDAO,
             aclMapper,
-            new CassandraSchemaVersionManager(versionDAO),
+            versionManager,
             CassandraConfiguration.DEFAULT_CONFIGURATION);
     }
 
@@ -799,23 +810,6 @@ class CassandraMailboxMapperTest {
     }
 
     @Test
-    void deleteShouldDeleteMailboxAndMailboxPathFromAllTables() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        mailboxPathV3DAO.save(MAILBOX)
-            .block();
-
-        testee.delete(MAILBOX).block();
-
-        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
-            .isEmpty();
-    }
-
-    @Test
     void findMailboxByPathShouldReturnMailboxWhenExistsInV1Table() {
         mailboxDAO.save(MAILBOX)
             .block();
@@ -920,62 +914,6 @@ class CassandraMailboxMapperTest {
     }
 
     @Test
-    void findMailboxWithPathLikeShouldReturnMailboxesWhenExistsInV1Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-
-        List<Mailbox> mailboxes = testee.findMailboxWithPathLike(MailboxQuery.builder()
-            .privateNamespace()
-            .username(USER)
-            .expression(Wildcard.INSTANCE)
-            .build()
-            .asUserBound())
-            .collectList().block();
-
-        assertThat(mailboxes).containsOnly(MAILBOX);
-    }
-
-    @Test
-    void findMailboxWithPathLikeShouldReturnMailboxesWhenExistsInBothTables() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-
-        List<Mailbox> mailboxes = testee.findMailboxWithPathLike(MailboxQuery.builder()
-            .privateNamespace()
-            .username(USER)
-            .expression(Wildcard.INSTANCE)
-            .build()
-            .asUserBound())
-            .collectList().block();
-
-        assertThat(mailboxes).containsOnly(MAILBOX);
-    }
-
-    @Test
-    void findMailboxWithPathLikeShouldReturnMailboxesWhenExistsInV2Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-
-        List<Mailbox> mailboxes = testee.findMailboxWithPathLike(MailboxQuery.builder()
-            .privateNamespace()
-            .username(USER)
-            .expression(Wildcard.INSTANCE)
-            .build()
-            .asUserBound())
-            .collectList().block();
-
-        assertThat(mailboxes).containsOnly(MAILBOX);
-    }
-
-    @Test
     void findMailboxWithPathLikeShouldReturnMailboxesWhenExistsInV3Table() {
         mailboxDAO.save(MAILBOX)
             .block();
@@ -995,65 +933,6 @@ class CassandraMailboxMapperTest {
     }
 
     @Test
-    void hasChildrenShouldReturnChildWhenExistsInV1Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        CassandraId childMailboxId = CassandraId.timeBased();
-        MailboxPath childMailboxPath = MailboxPath.forUser(USER, "name.child");
-        Mailbox childMailbox = new Mailbox(childMailboxPath, UID_VALIDITY, childMailboxId);
-        mailboxDAO.save(childMailbox)
-            .block();
-        mailboxPathDAO.save(childMailboxPath, childMailboxId)
-            .block();
-    
-        boolean hasChildren = testee.hasChildren(MAILBOX, '.').block();
-
-        assertThat(hasChildren).isTrue();
-    }
-
-    @Test
-    void hasChildrenShouldReturnChildWhenExistsInBothTables() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        CassandraId childMailboxId = CassandraId.timeBased();
-        MailboxPath childMailboxPath = MailboxPath.forUser(USER, "name.child");
-        Mailbox childMailbox = new Mailbox(childMailboxPath, UID_VALIDITY, childMailboxId);
-        mailboxDAO.save(childMailbox)
-            .block();
-        mailboxPathDAO.save(childMailboxPath, childMailboxId)
-            .block();
-
-        boolean hasChildren = testee.hasChildren(MAILBOX, '.').block();
-
-        assertThat(hasChildren).isTrue();
-    }
-
-    @Test
-    void hasChildrenShouldReturnChildWhenExistsInV2Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        CassandraId childMailboxId = CassandraId.timeBased();
-        MailboxPath childMailboxPath = MailboxPath.forUser(USER, "name.child");
-        Mailbox childMailbox = new Mailbox(childMailboxPath, UID_VALIDITY, childMailboxId);
-        mailboxDAO.save(childMailbox)
-            .block();
-        mailboxPathV2DAO.save(childMailboxPath, childMailboxId)
-            .block();
-    
-        boolean hasChildren = testee.hasChildren(MAILBOX, '.').block();
-    
-        assertThat(hasChildren).isTrue();
-    }
-
-    @Test
     void hasChildrenShouldReturnChildWhenExistsInV3Table() {
         mailboxDAO.save(MAILBOX)
             .block();
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/MailboxAggregateModule.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/MailboxAggregateModule.java
index dd1fd57..3b49629 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/MailboxAggregateModule.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/MailboxAggregateModule.java
@@ -22,6 +22,7 @@ package org.apache.james.mailbox.cassandra.mail;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.blob.cassandra.CassandraBlobModule;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraAnnotationModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraApplicableFlagsModule;
@@ -39,21 +40,22 @@ import org.apache.james.mailbox.cassandra.modules.CassandraUidModule;
 
 public interface MailboxAggregateModule {
     CassandraModule MODULE = CassandraModule.aggregateModules(
-            CassandraSchemaVersionModule.MODULE,
-            CassandraAclModule.MODULE,
-            CassandraMailboxModule.MODULE,
-            CassandraMessageModule.MODULE,
-            CassandraBlobModule.MODULE,
-            CassandraAttachmentModule.MODULE,
-            CassandraMailboxCounterModule.MODULE,
-            CassandraMailboxRecentsModule.MODULE,
-            CassandraFirstUnseenModule.MODULE,
-            CassandraUidModule.MODULE,
-            CassandraModSeqModule.MODULE,
-            CassandraSubscriptionModule.MODULE,
-            CassandraDeletedMessageModule.MODULE,
-            CassandraAnnotationModule.MODULE,
-            CassandraApplicableFlagsModule.MODULE);
+        CassandraAclModule.MODULE,
+        CassandraAnnotationModule.MODULE,
+        CassandraApplicableFlagsModule.MODULE,
+        CassandraAttachmentModule.MODULE,
+        CassandraBlobModule.MODULE,
+        CassandraEventStoreModule.MODULE(),
+        CassandraDeletedMessageModule.MODULE,
+        CassandraFirstUnseenModule.MODULE,
+        CassandraMailboxCounterModule.MODULE,
+        CassandraMailboxModule.MODULE,
+        CassandraMailboxRecentsModule.MODULE,
+        CassandraMessageModule.MODULE,
+        CassandraModSeqModule.MODULE,
+        CassandraSchemaVersionModule.MODULE,
+        CassandraSubscriptionModule.MODULE,
+        CassandraUidModule.MODULE);
 
     CassandraModule MODULE_WITH_QUOTA = CassandraModule.aggregateModules(CassandraQuotaModule.MODULE, MODULE);
 }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java
index 213df82..83c0c97 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AclV2MigrationTest.java
@@ -26,12 +26,20 @@ import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
+import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.core.Username;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStore;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreModule;
+import org.apache.james.eventsourcing.eventstore.cassandra.EventStoreDao;
+import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV2;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraMailboxDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraMailboxModule;
 import org.apache.james.mailbox.model.Mailbox;
@@ -52,8 +60,9 @@ class AclV2MigrationTest {
         UidValidity.generate(), MAILBOX_ID);
 
     public static final CassandraModule MODULES = CassandraModule.aggregateModules(
-        CassandraMailboxModule.MODULE,
         CassandraAclModule.MODULE,
+        CassandraEventStoreModule.MODULE(),
+        CassandraMailboxModule.MODULE,
         CassandraSchemaVersionModule.MODULE);
 
     @RegisterExtension
@@ -69,7 +78,14 @@ class AclV2MigrationTest {
         mailboxDAO = new CassandraMailboxDAO(cassandra.getConf(), cassandra.getTypesProvider(), CassandraConsistenciesConfiguration.DEFAULT);
         daoV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
         daoV2 = new CassandraACLDAOV2(cassandra.getConf());
-        migration = new AclV2Migration(mailboxDAO, daoV1, daoV2);
+        JsonEventSerializer jsonEventSerializer = JsonEventSerializer
+            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .withoutNestedType();
+        CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
+        CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+        migration = new AclV2Migration(mailboxDAO,
+            new CassandraACLMapper.StoreV1(usersRightDAO, daoV1),
+            new CassandraACLMapper.StoreV2(usersRightDAO, daoV2, eventStore));
     }
 
     @Test
@@ -105,7 +121,7 @@ class AclV2MigrationTest {
         MailboxACL acl = new MailboxACL(ImmutableMap.of(MailboxACL.EntryKey.createUserEntryKey(Username.of("alice")), MailboxACL.FULL_RIGHTS));
         daoV1.setACL(MAILBOX_ID, acl).block();
 
-        Task.Result result = migration.runTask();
+        migration.runTask();
 
         assertThat(daoV2.getACL(MAILBOX_ID).block()).isEqualTo(acl);
     }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
index 0d72d2b..86baa97 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
@@ -25,11 +25,16 @@ import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.core.Username;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStore;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreModule;
+import org.apache.james.eventsourcing.eventstore.cassandra.EventStoreDao;
+import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV2;
@@ -41,6 +46,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraMailboxPathDAOImpl;
 import org.apache.james.mailbox.cassandra.mail.CassandraMailboxPathV2DAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMailboxPathV3DAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraMailboxModule;
 import org.apache.james.mailbox.model.Mailbox;
@@ -62,7 +68,8 @@ class MailboxPathV2MigrationTest {
     public static final CassandraModule MODULES = CassandraModule.aggregateModules(
             CassandraMailboxModule.MODULE,
             CassandraAclModule.MODULE,
-            CassandraSchemaVersionModule.MODULE);
+            CassandraSchemaVersionModule.MODULE,
+            CassandraEventStoreModule.MODULE());
 
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULES);
@@ -94,6 +101,16 @@ class MailboxPathV2MigrationTest {
             cassandra.getConf(),
             cassandra.getTypesProvider(),
             cassandraCluster.getCassandraConsistenciesConfiguration());
+        CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(
+            cassandra.getConf(),
+            CassandraConfiguration.DEFAULT_CONFIGURATION,
+            cassandraCluster.getCassandraConsistenciesConfiguration());
+        CassandraACLDAOV2 aclDAOV2 = new CassandraACLDAOV2(cassandra.getConf());
+        JsonEventSerializer jsonEventSerializer = JsonEventSerializer
+            .forModules(ACLModule.ACL_RESET, ACLModule.ACL_UPDATE)
+            .withoutNestedType();
+        CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
+        CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
         mailboxMapper = new CassandraMailboxMapper(
             mailboxDAO,
             daoV1,
@@ -101,12 +118,8 @@ class MailboxPathV2MigrationTest {
             daoV3,
             userMailboxRightsDAO,
             new CassandraACLMapper(
-                userMailboxRightsDAO,
-                new CassandraACLDAOV1(
-                    cassandra.getConf(),
-                    CassandraConfiguration.DEFAULT_CONFIGURATION,
-                    cassandraCluster.getCassandraConsistenciesConfiguration()),
-                new CassandraACLDAOV2(cassandra.getConf()),
+                new CassandraACLMapper.StoreV1(usersRightDAO, aclDAOV1),
+                new CassandraACLMapper.StoreV2(usersRightDAO, aclDAOV2, eventStore),
                 new CassandraSchemaVersionManager(new CassandraSchemaVersionDAO(cassandra.getConf()))),
             new CassandraSchemaVersionManager(new CassandraSchemaVersionDAO(cassandra.getConf())),
             CassandraConfiguration.DEFAULT_CONFIGURATION);
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
index 6dc6dab..ad7fa95 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
@@ -19,6 +19,8 @@
 
 package org.apache.james.mailbox.cassandra.mail.utils;
 
+import java.util.Set;
+
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.init.CassandraTypesProvider;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
@@ -27,15 +29,28 @@ import org.apache.james.blob.api.BlobId;
 import org.apache.james.blob.api.BlobStore;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.cassandra.CassandraBlobStoreFactory;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStore;
+import org.apache.james.eventsourcing.eventstore.cassandra.EventNestedTypes;
+import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTO;
+import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTOModule;
+import org.apache.james.json.DTO;
+import org.apache.james.json.DTOModule;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLDAOV1;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.model.MessageId;
 
 import com.datastax.driver.core.Session;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Module;
+import com.google.inject.TypeLiteral;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
 import com.google.inject.util.Modules;
 
 public class GuiceUtils {
@@ -64,6 +79,14 @@ public class GuiceUtils {
             binder -> binder.bind(BlobId.Factory.class).toInstance(new HashBlobId.Factory()),
             binder -> binder.bind(BlobStore.class).toProvider(() -> CassandraBlobStoreFactory.forTesting(session).passthrough()),
             binder -> binder.bind(Session.class).toInstance(session),
+            binder -> Multibinder.newSetBinder(binder, new TypeLiteral<EventDTOModule<? extends Event, ? extends EventDTO>>() {})
+                .addBinding().toInstance(ACLModule.ACL_RESET),
+            binder -> Multibinder.newSetBinder(binder, new TypeLiteral<EventDTOModule<? extends Event, ? extends EventDTO>>() {})
+                .addBinding().toInstance(ACLModule.ACL_UPDATE),
+            binder -> binder.bind(new TypeLiteral<Set<DTOModule<?, ? extends DTO>>>() {}).annotatedWith(Names.named(EventNestedTypes.EVENT_NESTED_TYPES_INJECTION_NAME))
+                .toInstance(ImmutableSet.of()),
+            binder -> Multibinder.newSetBinder(binder, new TypeLiteral<EventDTOModule<? extends Event, ? extends EventDTO>>() {}),
+            binder -> binder.bind(EventStore.class).to(CassandraEventStore.class),
             binder -> binder.bind(CassandraTypesProvider.class).toInstance(typesProvider),
             binder -> binder.bind(CassandraConfiguration.class).toInstance(configuration),
             binder -> binder.bind(CassandraConsistenciesConfiguration.class)
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
index 5db0098..23408f1 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
@@ -25,6 +25,9 @@ import javax.inject.Singleton;
 import org.apache.james.adapter.mailbox.UserRepositoryAuthenticator;
 import org.apache.james.adapter.mailbox.UserRepositoryAuthorizator;
 import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTO;
+import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTOModule;
 import org.apache.james.mailbox.AttachmentContentLoader;
 import org.apache.james.mailbox.AttachmentManager;
 import org.apache.james.mailbox.Authenticator;
@@ -64,6 +67,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraModSeqProvider;
 import org.apache.james.mailbox.cassandra.mail.CassandraUidProvider;
 import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
+import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraAnnotationModule;
 import org.apache.james.mailbox.cassandra.modules.CassandraApplicableFlagsModule;
@@ -104,6 +108,7 @@ import org.apache.mailbox.tools.indexer.ReIndexerImpl;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Scopes;
+import com.google.inject.TypeLiteral;
 import com.google.inject.multibindings.Multibinder;
 import com.google.inject.name.Names;
 
@@ -206,6 +211,11 @@ public class CassandraMailboxModule extends AbstractModule {
         mailboxListeners.addBinding().to(DeleteMessageListener.class);
 
         bind(MailboxManager.class).annotatedWith(Names.named(MAILBOXMANAGER_NAME)).to(MailboxManager.class);
+
+        Multibinder.newSetBinder(binder(), new TypeLiteral<EventDTOModule<? extends Event, ? extends EventDTO>>() {})
+            .addBinding().toInstance(ACLModule.ACL_RESET);
+        Multibinder.newSetBinder(binder(), new TypeLiteral<EventDTOModule<? extends Event, ? extends EventDTO>>() {})
+            .addBinding().toInstance(ACLModule.ACL_UPDATE);
     }
     
     @Singleton
@@ -215,6 +225,4 @@ public class CassandraMailboxModule extends AbstractModule {
             super("cassandra-mailboxmanager", manager);
         }
     }
-    
-
 }


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


[james-project] 11/13: JAMES-3435 Pilot Cassandra mailbox ACL changes with an event sourcing system

Posted by bt...@apache.org.
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 f7b1bcc967079ca303c6aca0da7445f870e5acff
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sat Dec 5 09:46:30 2020 +0700

    JAMES-3435 Pilot Cassandra mailbox ACL changes with an event sourcing system
---
 .../mail/CassandraMailboxMapperGenericTest.java    |  23 +-
 .../mail/CassandraMailboxMapperV10Test.java        | 972 ---------------------
 2 files changed, 21 insertions(+), 974 deletions(-)

diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperGenericTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperGenericTest.java
index 673db45..04ca6aa 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperGenericTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperGenericTest.java
@@ -25,6 +25,7 @@ import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.apache.james.blob.cassandra.CassandraBlobModule;
+import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreModule;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.mail.utils.GuiceUtils;
 import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
@@ -39,11 +40,12 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 
 class CassandraMailboxMapperGenericTest {
     private static final CassandraModule MODULES = CassandraModule.aggregateModules(
-        CassandraBlobModule.MODULE,
-        CassandraSchemaVersionModule.MODULE,
         CassandraAclModule.MODULE,
+        CassandraBlobModule.MODULE,
+        CassandraEventStoreModule.MODULE(),
         CassandraMailboxModule.MODULE,
         CassandraModSeqModule.MODULE,
+        CassandraSchemaVersionModule.MODULE,
         CassandraUidModule.MODULE);
 
     @RegisterExtension
@@ -79,4 +81,21 @@ class CassandraMailboxMapperGenericTest {
             return CassandraId.timeBased();
         }
     }
+
+    @Nested
+    class V10 extends MailboxMapperTest {
+        @Override
+        protected MailboxMapper createMailboxMapper() {
+            new CassandraSchemaVersionDAO(cassandraCluster.getCassandraCluster().getConf())
+                .updateVersion(new SchemaVersion(10))
+                .block();
+            return GuiceUtils.testInjector(cassandraCluster.getCassandraCluster())
+                .getInstance(CassandraMailboxMapper.class);
+        }
+
+        @Override
+        protected MailboxId generateId() {
+            return CassandraId.timeBased();
+        }
+    }
 }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperV10Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperV10Test.java
deleted file mode 100644
index a1a644a..0000000
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperV10Test.java
+++ /dev/null
@@ -1,972 +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.mailbox.cassandra.mail;
-
-import static org.apache.james.backends.cassandra.Scenario.Builder.fail;
-import static org.apache.james.mailbox.model.MailboxAssertingTool.softly;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.util.List;
-import java.util.stream.IntStream;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.backends.cassandra.Scenario;
-import org.apache.james.backends.cassandra.components.CassandraModule;
-import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
-import org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
-import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
-import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
-import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
-import org.apache.james.backends.cassandra.versions.SchemaVersion;
-import org.apache.james.core.Username;
-import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStore;
-import org.apache.james.eventsourcing.eventstore.cassandra.CassandraEventStoreModule;
-import org.apache.james.eventsourcing.eventstore.cassandra.EventStoreDao;
-import org.apache.james.eventsourcing.eventstore.cassandra.JsonEventSerializer;
-import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.cassandra.mail.eventsourcing.acl.ACLModule;
-import org.apache.james.mailbox.cassandra.modules.CassandraAclModule;
-import org.apache.james.mailbox.cassandra.modules.CassandraMailboxModule;
-import org.apache.james.mailbox.exception.MailboxNotFoundException;
-import org.apache.james.mailbox.exception.TooLongMailboxNameException;
-import org.apache.james.mailbox.model.Mailbox;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.UidValidity;
-import org.apache.james.mailbox.model.search.ExactName;
-import org.apache.james.mailbox.model.search.MailboxQuery;
-import org.apache.james.mailbox.model.search.Wildcard;
-import org.apache.james.mailbox.store.MailboxReactorUtils;
-import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-import com.github.fge.lambdas.Throwing;
-import com.github.fge.lambdas.runnable.ThrowingRunnable;
-
-import reactor.core.publisher.Mono;
-
-class CassandraMailboxMapperV10Test {
-    private static final UidValidity UID_VALIDITY = UidValidity.of(52);
-    private static final Username USER = Username.of("user");
-    private static final CassandraId MAILBOX_ID = CassandraId.timeBased();
-    private static final MailboxPath MAILBOX_PATH = MailboxPath.forUser(USER, "name");
-    private static final Mailbox MAILBOX = new Mailbox(MAILBOX_PATH, UID_VALIDITY, MAILBOX_ID);
-    private static final String INBOX = "INBOX";
-    private static final String INBOX_RENAMED = "INBOX_RENAMED";
-
-    private static final CassandraId MAILBOX_ID_2 = CassandraId.timeBased();
-
-    private static final Mailbox MAILBOX_BIS = new Mailbox(MAILBOX_PATH, UID_VALIDITY, MAILBOX_ID_2);
-
-    private static final CassandraModule MODULES = CassandraModule.aggregateModules(
-        CassandraAclModule.MODULE,
-        CassandraEventStoreModule.MODULE(),
-        CassandraMailboxModule.MODULE,
-        CassandraSchemaVersionModule.MODULE);
-    private static final int TRY_COUNT_BEFORE_FAILURE = 6;
-
-    @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULES);
-
-    private CassandraMailboxDAO mailboxDAO;
-    private CassandraMailboxPathDAOImpl mailboxPathDAO;
-    private CassandraMailboxPathV2DAO mailboxPathV2DAO;
-    private CassandraMailboxPathV3DAO mailboxPathV3DAO;
-    private CassandraMailboxMapper testee;
-    private CassandraSchemaVersionDAO versionDAO;
-
-    @BeforeEach
-    void setUp() {
-        CassandraCluster cassandra = cassandraCluster.getCassandraCluster();
-        mailboxDAO = new CassandraMailboxDAO(cassandra.getConf(), cassandra.getTypesProvider(), cassandraCluster.getCassandraConsistenciesConfiguration());
-        mailboxPathDAO = new CassandraMailboxPathDAOImpl(cassandra.getConf(), cassandra.getTypesProvider(), cassandraCluster.getCassandraConsistenciesConfiguration());
-        mailboxPathV2DAO = new CassandraMailboxPathV2DAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION, cassandraCluster.getCassandraConsistenciesConfiguration());
-        mailboxPathV3DAO = new CassandraMailboxPathV3DAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION, cassandraCluster.getCassandraConsistenciesConfiguration());
-
-        versionDAO = new CassandraSchemaVersionDAO(cassandra.getConf());
-        versionDAO.truncateVersion()
-            .then(versionDAO.updateVersion(new SchemaVersion(10)))
-            .block();
-        CassandraSchemaVersionManager versionManager = new CassandraSchemaVersionManager(versionDAO);
-
-        CassandraACLDAOV1 aclDAOV1 = new CassandraACLDAOV1(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION, CassandraConsistenciesConfiguration.DEFAULT);
-        CassandraACLDAOV2 aclDAOv2 = new CassandraACLDAOV2(cassandra.getConf());
-        JsonEventSerializer jsonEventSerializer = JsonEventSerializer
-            .forModules(ACLModule.ACL_UPDATE)
-            .withoutNestedType();
-        CassandraUserMailboxRightsDAO usersRightDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
-        CassandraEventStore eventStore = new CassandraEventStore(new EventStoreDao(cassandra.getConf(), jsonEventSerializer, CassandraConsistenciesConfiguration.DEFAULT));
-        CassandraACLMapper aclMapper = new CassandraACLMapper(
-            new CassandraACLMapper.StoreV1(usersRightDAO, aclDAOV1),
-            new CassandraACLMapper.StoreV2(usersRightDAO, aclDAOv2, eventStore),
-            versionManager);
-        testee = new CassandraMailboxMapper(
-            mailboxDAO,
-            mailboxPathDAO,
-            mailboxPathV2DAO,
-            mailboxPathV3DAO,
-            usersRightDAO,
-            aclMapper,
-            versionManager,
-            CassandraConfiguration.DEFAULT_CONFIGURATION);
-    }
-
-    @Nested
-    class ConsistencyTest {
-
-        private MailboxPath inboxPath;
-        private MailboxPath inboxPathRenamed;
-        private MailboxQuery.UserBound allMailboxesSearchQuery;
-        private MailboxQuery.UserBound inboxSearchQuery;
-        private MailboxQuery.UserBound inboxRenamedSearchQuery;
-
-        @BeforeEach
-        void setUp() {
-            inboxPath = MailboxPath.forUser(USER, INBOX);
-            inboxPathRenamed = MailboxPath.forUser(USER, INBOX_RENAMED);
-            allMailboxesSearchQuery = MailboxQuery.builder()
-                .userAndNamespaceFrom(inboxPath)
-                .expression(Wildcard.INSTANCE)
-                .build()
-                .asUserBound();
-            inboxSearchQuery = MailboxQuery.builder()
-                .userAndNamespaceFrom(inboxPath)
-                .expression(new ExactName(INBOX))
-                .build()
-                .asUserBound();
-            inboxRenamedSearchQuery = MailboxQuery.builder()
-                .userAndNamespaceFrom(inboxPathRenamed)
-                .expression(new ExactName(INBOX_RENAMED))
-                .build()
-                .asUserBound();
-        }
-
-        @Nested
-        class Retries {
-            @Test
-            void renameShouldRetryFailedDeleteMailboxPath(CassandraCluster cassandra) {
-                Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-                MailboxId inboxId = inbox.getMailboxId();
-                Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
-
-                cassandra.getConf()
-                    .registerScenario(fail()
-                        .times(1)
-                        .whenQueryStartsWith("DELETE FROM mailboxPathV2 WHERE namespace=:namespace AND user=:user AND mailboxName=:mailboxName IF EXISTS;"));
-
-                testee.rename(inboxRenamed).block();
-
-                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                    softly(softly)
-                        .assertThat(testee.findMailboxById(inboxId).block())
-                        .isEqualTo(inboxRenamed);
-                    softly(softly)
-                        .assertThat(testee.findMailboxByPath(inboxPathRenamed).block())
-                        .isEqualTo(inboxRenamed);
-                    softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                        .collectList().block())
-                        .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                            .assertThat(searchMailbox)
-                            .isEqualTo(inboxRenamed));
-                }));
-            }
-
-            @Test
-            void renameShouldRetryFailedMailboxSaving(CassandraCluster cassandra) {
-                Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-                MailboxId inboxId = inbox.getMailboxId();
-                Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
-
-                cassandra.getConf()
-                    .registerScenario(fail()
-                        .times(1)
-                        .whenQueryStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);"));
-
-                testee.rename(inboxRenamed).block();
-
-                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                    softly(softly)
-                        .assertThat(testee.findMailboxById(inboxId).block())
-                        .isEqualTo(inboxRenamed);
-                    softly(softly)
-                        .assertThat(testee.findMailboxByPath(inboxPathRenamed).block())
-                        .isEqualTo(inboxRenamed);
-                    softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                        .collectList().block())
-                        .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                            .assertThat(searchMailbox)
-                            .isEqualTo(inboxRenamed));
-                }));
-            }
-
-            @Test
-            void createShouldRetryFailedMailboxSaving(CassandraCluster cassandra) {
-                cassandra.getConf()
-                    .registerScenario(fail()
-                        .times(1)
-                        .whenQueryStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);"));
-
-                Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-
-                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                    softly(softly)
-                        .assertThat(testee.findMailboxById(inbox.getMailboxId()).block())
-                        .isEqualTo(inbox);
-                    softly(softly)
-                        .assertThat(testee.findMailboxByPath(inboxPath).block())
-                        .isEqualTo(inbox);
-                    softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                        .collectList().block())
-                        .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                            .assertThat(searchMailbox)
-                            .isEqualTo(inbox));
-                }));
-            }
-
-            @Test
-            void deleteShouldRetryFailedMailboxDeletion(CassandraCluster cassandra) {
-                Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-
-                cassandra.getConf()
-                    .registerScenario(fail()
-                        .times(1)
-                        .whenQueryStartsWith("DELETE FROM mailbox WHERE id=:id;"));
-
-                testee.delete(inbox).block();
-
-                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                    softly.assertThatThrownBy(() -> testee.findMailboxById(inbox.getMailboxId()).block())
-                        .hasCauseInstanceOf(MailboxNotFoundException.class);
-                    softly.assertThat(testee.findMailboxByPath(inboxPath).blockOptional())
-                        .isEmpty();
-                    softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                        .collectList().block())
-                        .isEmpty();
-                }));
-            }
-        }
-
-        @Nested
-        class ReadRepairs {
-            @Test
-            void findMailboxByIdShouldEventuallyFixInconsistencyWhenMailboxIsNotInPath() {
-                mailboxDAO.save(MAILBOX)
-                    .block();
-
-                IntStream.range(0, 100).forEach(i ->
-                    testee.findMailboxById(MAILBOX_ID)
-                        .onErrorResume(e -> Mono.empty())
-                        .block());
-
-                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                    softly(softly)
-                        .assertThat(testee.findMailboxById(MAILBOX_ID).block())
-                        .isEqualTo(MAILBOX);
-                    softly(softly)
-                        .assertThat(testee.findMailboxByPath(MAILBOX_PATH).block())
-                        .isEqualTo(MAILBOX);
-                }));
-            }
-
-            @Test
-            void orphanMailboxIdEntriesCanNotBeReadRepaired() {
-                mailboxDAO.save(MAILBOX)
-                    .block();
-
-                IntStream.range(0, 100).forEach(i ->
-                    testee.findMailboxByPath(MAILBOX_PATH)
-                        .onErrorResume(e -> Mono.empty())
-                        .block());
-
-                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                    softly.assertThat(MailboxReactorUtils.blockOptional(testee.findMailboxByPath(MAILBOX_PATH)))
-                        .isEmpty();
-                    softly(softly)
-                        .assertThat(testee.findMailboxById(MAILBOX_ID).block())
-                        .isEqualTo(MAILBOX);
-                }));
-            }
-
-            @Test
-            void orphanPathEntriesCanNotBeRepairedByIdReads() {
-                mailboxPathV3DAO.save(MAILBOX)
-                    .block();
-
-                IntStream.range(0, 100).forEach(i ->
-                    testee.findMailboxById(MAILBOX_ID)
-                        .onErrorResume(e -> Mono.empty())
-                        .block());
-
-                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                    softly.assertThatThrownBy(() -> MailboxReactorUtils.blockOptional(testee.findMailboxById(MAILBOX_ID)))
-                        .isInstanceOf(MailboxNotFoundException.class);
-                    softly(softly)
-                        .assertThat(testee.findMailboxByPath(MAILBOX_PATH).block())
-                        .isEqualTo(MAILBOX);
-                }));
-            }
-
-            @Test
-            void findMailboxByPathShouldFixInconsistencyWhenMailboxIsNotReferencedById() {
-                mailboxPathV3DAO.save(MAILBOX)
-                    .block();
-
-                IntStream.range(0, 100).forEach(i ->
-                    testee.findMailboxByPath(MAILBOX_PATH)
-                        .onErrorResume(e -> Mono.empty())
-                        .block());
-
-                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                    softly.assertThatThrownBy(() -> MailboxReactorUtils.blockOptional(testee.findMailboxById(MAILBOX_ID)))
-                        .isInstanceOf(MailboxNotFoundException.class);
-                    softly.assertThat(MailboxReactorUtils.blockOptional(testee.findMailboxByPath(MAILBOX_PATH)))
-                        .isEmpty();
-                }));
-            }
-        }
-
-        @Disabled("In order to be more performant mailboxPath V3 table includes the UID_VALIDITY." +
-            "Reading paths no longer requires reading the mailbox by id but this of course has a " +
-            "consistency cost.")
-        @Test
-        void createShouldBeConsistentWhenFailToPersistMailbox(CassandraCluster cassandra) {
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(10)
-                    .whenQueryStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);"));
-
-            doQuietly(() -> testee.create(inboxPath, UID_VALIDITY).block());
-
-            SoftAssertions.assertSoftly(softly -> {
-                softly.assertThat(testee.findMailboxByPath(inboxPath).blockOptional())
-                    .isEmpty();
-                softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery)
-                    .collectList().block())
-                    .isEmpty();
-                softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                    .collectList().block())
-                    .isEmpty();
-            });
-        }
-
-        @Test
-        void renameThenFailToRetrieveMailboxShouldBeConsistentWhenFindByInbox(CassandraCluster cassandra) {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-            Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
-
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("SELECT id,mailboxbase,uidvalidity,name FROM mailbox WHERE id=:id;"));
-
-            doQuietly(() -> testee.rename(inboxRenamed));
-
-            cassandra.getConf().registerScenario(Scenario.NOTHING);
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                softly(softly)
-                    .assertThat(testee.findMailboxById(inboxId).block())
-                    .isEqualTo(inbox);
-                softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPath).block())
-                    .isEqualTo(inbox);
-                softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inbox));
-            }));
-        }
-
-        @Disabled("JAMES-3056 returning two mailboxes with same name and id")
-        @Test
-        void renameThenFailToRetrieveMailboxShouldBeConsistentWhenFindAll(CassandraCluster cassandra) {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-            Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
-
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("SELECT id,mailboxbase,uidvalidity,name FROM mailbox WHERE id=:id;"));
-
-            doQuietly(() -> testee.rename(inboxRenamed).block());
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly ->
-                softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inbox))
-            ));
-        }
-
-        @Disabled("JAMES-3056 find by renamed name returns unexpected results")
-        @Test
-        void renameThenFailToRetrieveMailboxShouldBeConsistentWhenFindByRenamedInbox(CassandraCluster cassandra) {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-            Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
-
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("SELECT id,mailboxbase,uidvalidity,name FROM mailbox WHERE id=:id;"));
-
-            doQuietly(() -> testee.rename(inboxRenamed).block());
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                softly.assertThatThrownBy(() -> testee.findMailboxByPath(inboxPathRenamed).block())
-                    .isInstanceOf(MailboxNotFoundException.class);
-                softly.assertThat(testee.findMailboxWithPathLike(inboxRenamedSearchQuery)
-                    .collectList().block())
-                    .isEmpty();
-            }));
-        }
-
-        @Test
-        void renameThenFailToDeleteMailboxPathShouldBeConsistentWhenFindByInbox(CassandraCluster cassandra) {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-            Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
-
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("DELETE FROM mailboxPathV3 WHERE namespace=:namespace AND user=:user AND mailboxName=:mailboxName IF EXISTS;"));
-
-            doQuietly(() -> testee.rename(inboxRenamed).block());
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                softly(softly)
-                    .assertThat(testee.findMailboxById(inboxId).block())
-                    .isEqualTo(inbox);
-                softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPath).block())
-                    .isEqualTo(inbox);
-                softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inbox));
-            }));
-        }
-
-        @Disabled("JAMES-3056 returning two mailboxes with same name and id")
-        @Test
-        void renameThenFailToDeleteMailboxPathShouldBeConsistentWhenFindAll(CassandraCluster cassandra) {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-            Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
-
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("DELETE FROM mailboxPathV3 WHERE namespace=:namespace AND user=:user AND mailboxName=:mailboxName IF EXISTS;"));
-
-            doQuietly(() -> testee.rename(inboxRenamed).block());
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly ->
-                softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inbox))));
-        }
-
-        @Disabled("JAMES-3056 find by renamed name returns unexpected results")
-        @Test
-        void renameThenFailToDeleteMailboxPathShouldBeConsistentWhenFindByRenamedInbox(CassandraCluster cassandra) {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-            Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
-
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("DELETE FROM mailboxPathV3 WHERE namespace=:namespace AND user=:user AND mailboxName=:mailboxName IF EXISTS;"));
-
-            doQuietly(() -> testee.rename(inboxRenamed).block());
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                softly.assertThatThrownBy(() -> testee.findMailboxByPath(inboxPathRenamed).block())
-                    .isInstanceOf(MailboxNotFoundException.class);
-                softly.assertThat(testee.findMailboxWithPathLike(inboxRenamedSearchQuery)
-                    .collectList().block())
-                    .isEmpty();
-            }));
-        }
-
-        @Disabled("JAMES-3056 find by mailbox name returns unexpected results")
-        @Test
-        void deleteShouldBeConsistentWhenFailToDeleteMailbox(CassandraCluster cassandra) {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("DELETE FROM mailbox WHERE id=:id;"));
-
-            doQuietly(() -> testee.delete(inbox).block());
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                softly.assertThatCode(() -> testee.findMailboxById(inboxId).block())
-                    .doesNotThrowAnyException();
-                softly.assertThatCode(() -> testee.findMailboxByPath(inboxPath).block())
-                    .doesNotThrowAnyException();
-                softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inbox));
-                softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inbox));
-            }));
-        }
-
-        @Disabled("JAMES-3056 both mailboxes of the same user have 'INBOX' name")
-        @Test
-        void missedMigrationShouldNotLeadToGhostMailbox() {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-            // simulate mailbox old data has not been migrated to v2
-            mailboxPathDAO.save(inboxPath, inboxId).block();
-            mailboxPathV3DAO.delete(inboxPath).block();
-
-            // on current v2 generation, save a new mailbox with the exactly name
-            // => two mailboxes with same name but different ids
-            CassandraId newId = CassandraId.timeBased();
-            Mailbox mailboxHasSameNameWithInbox = new Mailbox(inboxPath, UID_VALIDITY, newId);
-            testee.rename(mailboxHasSameNameWithInbox).block();
-
-            assertThat(testee.findMailboxById(newId).block().getName())
-                .isNotEqualTo(testee.findMailboxById(inboxId).block().getName());
-        }
-
-        @Disabled("JAMES-3056 org.apache.james.mailbox.exception.MailboxNotFoundException: 'mailboxId' can not be found")
-        @Test
-        void createAfterPreviousFailedCreateShouldCreateAMailbox(CassandraCluster cassandra) {
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);"));
-
-            doQuietly(() -> testee.create(inboxPath, UID_VALIDITY).block());
-
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPath).block())
-                    .isEqualTo(inbox);
-                softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inbox));
-                softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inbox));
-            }));
-        }
-
-        @Test
-        void createAfterPreviousDeleteOnFailedCreateShouldCreateAMailbox(CassandraCluster cassandra) {
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);"));
-
-            doQuietly(() -> testee.create(inboxPath, UID_VALIDITY).block());
-            doQuietly(() -> testee.delete(new Mailbox(inboxPath, UID_VALIDITY, CassandraId.timeBased())).block());
-
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPath).block())
-                    .isEqualTo(inbox);
-                softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inbox));
-                softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inbox));
-            }));
-        }
-
-        @Test
-        void deleteAfterAFailedDeleteShouldDeleteTheMailbox(CassandraCluster cassandra) {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("DELETE FROM mailbox WHERE id=:id;"));
-
-            doQuietly(() -> testee.delete(inbox).block());
-
-            doQuietly(() -> testee.delete(inbox).block());
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                softly.assertThatThrownBy(() -> testee.findMailboxById(inboxId).block())
-                    .hasCauseInstanceOf(MailboxNotFoundException.class);
-                    softly.assertThat(testee.findMailboxByPath(inboxPath).blockOptional())
-                        .isEmpty();
-                softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery)
-                    .collectList().block())
-                    .isEmpty();
-                softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                    .collectList().block())
-                    .isEmpty();
-            }));
-        }
-
-        @Disabled("JAMES-3056 mailbox name is not updated to INBOX_RENAMED).isEqualTo(" +
-            "findMailboxWithPathLike() returns a list with two same mailboxes")
-        @Test
-        void renameAfterRenameFailOnRetrieveMailboxShouldRenameTheMailbox(CassandraCluster cassandra) {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-            Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
-
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("SELECT id,mailboxbase,uidvalidity,name FROM mailbox WHERE id=:id;"));
-
-            doQuietly(() -> testee.rename(inboxRenamed).block());
-
-            doQuietly(() -> testee.rename(inboxRenamed).block());
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                softly(softly)
-                    .assertThat(testee.findMailboxById(inboxId).block())
-                    .isEqualTo(inboxRenamed);
-                softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPathRenamed).block())
-                    .isEqualTo(inboxRenamed);
-                softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery)
-                    .collectList().block())
-                    .isEmpty();
-                softly.assertThat(testee.findMailboxWithPathLike(inboxRenamedSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inboxRenamed));
-                softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inboxRenamed));
-            }));
-        }
-
-        @Disabled("JAMES-3056 mailbox name is not updated to INBOX_RENAMED")
-        @Test
-        void renameAfterRenameFailOnDeletePathShouldRenameTheMailbox(CassandraCluster cassandra) {
-            Mailbox inbox = testee.create(inboxPath, UID_VALIDITY).block();
-            CassandraId inboxId = (CassandraId) inbox.getMailboxId();
-            Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
-
-            cassandra.getConf()
-                .registerScenario(fail()
-                    .times(TRY_COUNT_BEFORE_FAILURE)
-                    .whenQueryStartsWith("DELETE FROM mailboxPathV3 WHERE namespace=:namespace AND user=:user AND mailboxName=:mailboxName IF EXISTS;"));
-
-            doQuietly(() -> testee.rename(inboxRenamed).block());
-
-            doQuietly(() -> testee.rename(inboxRenamed).block());
-
-            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                softly(softly)
-                    .assertThat(testee.findMailboxById(inboxId).block())
-                    .isEqualTo(inboxRenamed);
-                softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPathRenamed).block())
-                    .isEqualTo(inboxRenamed);
-                softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery)
-                    .collectList().block())
-                    .isEmpty();
-                softly.assertThat(testee.findMailboxWithPathLike(inboxRenamedSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox ->
-                        softly(softly)
-                            .assertThat(searchMailbox)
-                            .isEqualTo(inboxRenamed));
-                softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery)
-                    .collectList().block())
-                    .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
-                        .assertThat(searchMailbox)
-                        .isEqualTo(inboxRenamed));
-            }));
-        }
-
-        private void doQuietly(ThrowingRunnable runnable) {
-            try {
-                runnable.run();
-            } catch (Throwable th) {
-                // ignore
-            }
-        }
-
-        private Mailbox createInboxRenamedMailbox(MailboxId mailboxId) {
-            return new Mailbox(inboxPathRenamed, UID_VALIDITY, mailboxId);
-        }
-    }
-
-    @Disabled("JAMES-2514 Cassandra 3 supports long mailbox names. Hence we can not rely on this for failing")
-    @Test
-    void renameShouldNotRemoveOldMailboxPathWhenCreatingTheNewMailboxPathFails() {
-        testee.create(MAILBOX_PATH, UID_VALIDITY).block();
-        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH).block();
-
-        Mailbox newMailbox = new Mailbox(tooLongMailboxPath(mailbox.generateAssociatedPath()), UID_VALIDITY, mailbox.getMailboxId());
-        assertThatThrownBy(() -> testee.rename(newMailbox).block())
-            .isInstanceOf(TooLongMailboxNameException.class);
-
-        assertThat(mailboxPathV3DAO.retrieve(MAILBOX_PATH).blockOptional())
-            .isPresent();
-    }
-
-    private MailboxPath tooLongMailboxPath(MailboxPath fromMailboxPath) {
-        return new MailboxPath(fromMailboxPath, StringUtils.repeat("b", 65537));
-    }
-
-    @Test
-    void deleteShouldDeleteMailboxAndMailboxPathFromV1Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-
-        testee.delete(MAILBOX).block();
-
-        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
-            .isEmpty();
-    }
-
-    @Test
-    void deleteShouldDeleteMailboxAndMailboxPathFromV2Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-
-        testee.delete(MAILBOX).block();
-
-        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
-            .isEmpty();
-    }
-
-    @Test
-    void deleteShouldDeleteMailboxAndMailboxPathFromV3Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathV3DAO.save(MAILBOX)
-            .block();
-
-        testee.delete(MAILBOX).block();
-
-        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
-            .isEmpty();
-    }
-
-    @Test
-    void findMailboxByPathShouldReturnMailboxWhenExistsInV1Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-
-        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH).block();
-
-        assertThat(mailbox.generateAssociatedPath()).isEqualTo(MAILBOX_PATH);
-    }
-
-    @Test
-    void findMailboxByPathShouldReturnMailboxWhenExistsInV2Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-
-        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH).block();
-
-        assertThat(mailbox.generateAssociatedPath()).isEqualTo(MAILBOX_PATH);
-    }
-
-    @Test
-    void findMailboxByPathShouldReturnMailboxWhenExistsInV3Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathV3DAO.save(MAILBOX)
-            .block();
-
-        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH).block();
-
-        assertThat(mailbox.generateAssociatedPath()).isEqualTo(MAILBOX_PATH);
-    }
-
-    @Test
-    void findMailboxByPathShouldReturnMailboxWhenExistsInAllTables() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        mailboxPathV3DAO.save(MAILBOX)
-            .block();
-
-        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH).block();
-
-        assertThat(mailbox.generateAssociatedPath()).isEqualTo(MAILBOX_PATH);
-    }
-
-    @Test
-    void deleteShouldRemoveMailboxWhenInAllTables() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-        mailboxPathV3DAO.save(MAILBOX)
-            .block();
-
-        testee.delete(MAILBOX).block();
-
-        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
-            .isEmpty();
-    }
-
-    @Test
-    void deleteShouldRemoveMailboxWhenInV1Tables() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-
-        testee.delete(MAILBOX).block();
-
-        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
-            .isEmpty();
-    }
-
-    @Test
-    void deleteShouldRemoveMailboxWhenInV2Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .block();
-
-        testee.delete(MAILBOX).block();
-
-        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
-            .isEmpty();
-    }
-
-    @Test
-    void findMailboxByPathShouldThrowWhenDoesntExistInBothTables() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-
-        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
-            .isEmpty();
-    }
-
-    @Test
-    void findMailboxWithPathLikeShouldReturnMailboxesWhenExistsInV3Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathV3DAO.save(MAILBOX)
-            .block();
-
-        List<Mailbox> mailboxes = testee.findMailboxWithPathLike(MailboxQuery.builder()
-            .privateNamespace()
-            .username(USER)
-            .expression(Wildcard.INSTANCE)
-            .build()
-            .asUserBound())
-            .collectList()
-            .block();
-
-        assertThat(mailboxes).containsOnly(MAILBOX);
-    }
-
-    @Test
-    void hasChildrenShouldReturnChildWhenExistsInV3Table() {
-        mailboxDAO.save(MAILBOX)
-            .block();
-        mailboxPathV3DAO.save(MAILBOX)
-            .block();
-        CassandraId childMailboxId = CassandraId.timeBased();
-        MailboxPath childMailboxPath = MailboxPath.forUser(USER, "name.child");
-        Mailbox childMailbox = new Mailbox(childMailboxPath, UID_VALIDITY, childMailboxId);
-        mailboxDAO.save(childMailbox)
-            .block();
-        mailboxPathV3DAO.save(childMailbox)
-            .block();
-
-        boolean hasChildren = testee.hasChildren(MAILBOX, '.').block();
-
-        assertThat(hasChildren).isTrue();
-    }
-
-    @Test
-    void findMailboxWithPathLikeShouldRemoveDuplicatesAndKeepV3() {
-        mailboxDAO.save(MAILBOX).block();
-        mailboxPathV3DAO.save(MAILBOX).block();
-
-        mailboxDAO.save(MAILBOX_BIS).block();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID_2).block();
-
-        assertThat(testee.findMailboxWithPathLike(
-            MailboxQuery.builder()
-                .privateNamespace()
-                .username(USER)
-                .expression(Wildcard.INSTANCE)
-                .build()
-                .asUserBound())
-            .collectList().block())
-            .containsOnly(MAILBOX);
-    }
-}


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


[james-project] 12/13: JAMES-3435 CHANGELOG.md & upgrade-instructions.md

Posted by bt...@apache.org.
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 51cd0a5b355ee438d7a7bef06179a888a6f65113
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sat Dec 5 09:53:32 2020 +0700

    JAMES-3435 CHANGELOG.md & upgrade-instructions.md
---
 CHANGELOG.md            |  1 +
 upgrade-instructions.md | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 596bcc0..7ee7c1c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,6 +28,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 - JAMES-3176 Rewritte MDN parsing with Parboiled scala (avoid asm library dependency clash within the Distributed Server)
 - JAMES-3194 Rely on DTOConverter in TaskRoute
 - JAMES-3430 Restructure message properties storage within Cassandra Mailbox. See upgrade instructions.
+- JAMES-3435 Use EventSourcing to manage ACL - avoid SERIAL reads for ACL thus unlocking a performance enhancement for the Distributed James server. Read upgrade instructions.
 
 ### Deprecated
 - HybridBlobStore. This will be removed after 3.6.0 release. Introduced to fasten small blob access, its usage could be
diff --git a/upgrade-instructions.md b/upgrade-instructions.md
index 3ba7aef..7918bea 100644
--- a/upgrade-instructions.md
+++ b/upgrade-instructions.md
@@ -23,6 +23,21 @@ Change list:
  - [Cassandra Schema update to V8](#cassandra-schema-update-to-v8)
  - [Cassandra Schema update to V9](#cassandra-schema-update-to-v9)
 
+### Cassandra Schema update to V10
+
+Date 05/12/2020
+
+JIRA: https://issues.apache.org/jira/browse/JAMES-3435
+
+Concerned product: Distributed James
+
+Handles Mailbox ACL transactionality with event-sourcing. We got read of SERIAL consistency upon reads thus unlocking a
+major performance enhancement.
+
+In order to benefit from this work, you need to [upgrade to the latest schema version](https://github.com/apache/james-project/blob/master/src/site/markdown/server/manage-webadmin.md#upgrading-to-the-latest-version).
+
+A James restart is advised after this migration in order to skip schema version reads.
+
 ### Cassandra Schema update to V9
 
 Date 20/10/2020
@@ -47,6 +62,8 @@ Add UID_VALIDITY to mailboxPath table in order not to mandate mailbox table read
 
 In order to benefit from this work, you need to [upgrade to the latest schema version](https://github.com/apache/james-project/blob/master/src/site/markdown/server/manage-webadmin.md#upgrading-to-the-latest-version).
 
+A James restart is advised after this migration in order to skip schema version reads.
+
 ### Swift support has been dropped
 
 Date 14/09/2020


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