You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/05/07 02:12:24 UTC

[james-project] branch master updated (6874425 -> 59a0b23)

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 6874425  [Refactoring] LuceneMailboxMessageSearchIndexTest: UTF-8 static import
     new e1e8c12  JAMES-3140 Add a way of parsing Size units
     new c3fa195  [Documentation] Fix README docker compilation path
     new cb1380d  JAMES-3148 [ADR] Cassandra metadata cleanup upon deletion
     new 30d9745  JAMES-3148 FunctionalUtils negate helper
     new a6b44ca  JAMES-3148 MessageRepresentation should only ship information stored in CassandraMessageDAO
     new 15ddca9  JAMES-3148 CassandraMessageDAO::delete
     new 4859722  JAMES-3148 CassandraMessageDAO::delete
     new a42e36e  JAMES-3148 Add a listener for cleaning mailbox/cassandra upon deletions
     new 3098849  JAMES-3148 Also cleanup AttachmentMessageIdDAO upon deletion
     new 0192d70  JAMES-3148 Test and correct metadata cleanup upon failures
     new 5bddcdc  JAMES-3148 ACL deletion
     new a26512a  JAMES-3148 ACL mapper should not position default value
     new 456e83e  JAMES-3148 ACL cleanUp upon mailbox deletion
     new d1dc8ad  JAMES-3148 Cleanup ApplicableFlags
     new 05bd2f6  JAMES-3148 Cleanup First Unseen DAO
     new 03d0cf4  JAMES-3148 Cleanup Deleted Messages DAO
     new 1df0a9f  JAMES-3148 Cleanup MailboxCounters DAO
     new eb4633e  JAMES-3148 Cleanup Mailbox recents DAO
     new ecbbc2f  JAMES-3148 Readability enhencements: method extractions and renames
     new f4ceba7  JAMES-3148 DeleteMessageListener: Add class javaDoc
     new 48daa66  JAMES-3148 Readability enhencements: method rename and extraction
     new 59a0b23  JAMES-3148 DeletionTests should leverage the use of AppendResult

The 22 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:
 README.adoc                                        |  10 +-
 .../apache/james/mailbox/MailboxManagerTest.java   |   4 +-
 .../CassandraMailboxSessionMapperFactory.java      |   6 +
 .../mailbox/cassandra/DeleteMessageListener.java   | 223 +++++++
 .../mailbox/cassandra/mail/AttachmentLoader.java   |   9 +-
 .../mailbox/cassandra/mail/CassandraACLMapper.java |  19 +-
 .../cassandra/mail/CassandraApplicableFlagDAO.java |  15 +
 .../cassandra/mail/CassandraAttachmentDAOV2.java   |  14 +
 .../mail/CassandraAttachmentMessageIdDAO.java      |  18 +
 .../cassandra/mail/CassandraDeletedMessageDAO.java |  13 +
 .../cassandra/mail/CassandraFirstUnseenDAO.java    |  13 +
 .../cassandra/mail/CassandraMailboxCounterDAO.java |   8 +
 .../cassandra/mail/CassandraMailboxMapper.java     |   9 +-
 .../cassandra/mail/CassandraMailboxRecentsDAO.java |  18 +-
 .../cassandra/mail/CassandraMessageDAO.java        |  24 +-
 .../cassandra/mail/CassandraMessageIdMapper.java   |   3 +-
 .../cassandra/mail/CassandraMessageMapper.java     |   7 +-
 .../cassandra/mail/MessageRepresentation.java      |  34 +-
 .../mail/task/MailboxMergingTaskRunner.java        |   8 +-
 .../cassandra/CassandraMailboxManagerProvider.java |   1 +
 .../cassandra/CassandraMailboxManagerTest.java     | 742 +++++++++++++++++++++
 .../cassandra/CassandraTestSystemFixture.java      |   1 +
 .../cassandra/mail/CassandraACLMapperTest.java     |  22 +-
 .../mail/CassandraApplicableFlagDAOTest.java       |  16 +
 .../mail/CassandraAttachmentDAOV2Test.java         |  25 +
 .../mail/CassandraAttachmentMessageIdDAOTest.java  |  37 +
 .../mail/CassandraDeletedMessageDAOTest.java       |  20 +
 .../mail/CassandraFirstUnseenDAOTest.java          |  27 +
 .../mail/CassandraMailboxCounterDAOTest.java       |  17 +
 .../mail/CassandraMailboxRecentDAOTest.java        |  47 +-
 .../modules/mailbox/CassandraMailboxModule.java    |   7 +-
 .../java/org/apache/james/util/DurationParser.java |  35 +-
 .../org/apache/james/util/FunctionalUtils.java     |   5 +
 .../java/org/apache/james/util/SizeFormat.java     |  25 +-
 .../java/org/apache/james/util/UnitParser.java     |  64 ++
 .../java/org/apache/james/util/SizeFormatTest.java |  60 ++
 .../jmap/http/DefaultMailboxesProvisioner.java     |   4 +-
 .../view/cassandra/CassandraMailQueueView.java     |   4 +-
 .../rabbitmq/view/cassandra/DeletedMailsDAO.java   |   3 +-
 src/adr/0029-Cassandra-mailbox-deletion-cleanup.md |  44 ++
 40 files changed, 1545 insertions(+), 116 deletions(-)
 create mode 100644 mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
 create mode 100644 server/container/util/src/main/java/org/apache/james/util/UnitParser.java
 create mode 100644 src/adr/0029-Cassandra-mailbox-deletion-cleanup.md


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


[james-project] 12/22: JAMES-3148 ACL mapper should not position default value

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 a26512a2ba9cff835aebfaf357017840bef1d6b7
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 16:48:20 2020 +0700

    JAMES-3148 ACL mapper should not position default value
---
 .../apache/james/mailbox/cassandra/mail/CassandraACLMapper.java  | 3 +--
 .../james/mailbox/cassandra/mail/CassandraMailboxMapper.java     | 9 +++++++--
 .../mailbox/cassandra/mail/task/MailboxMergingTaskRunner.java    | 8 ++++++--
 .../james/mailbox/cassandra/mail/CassandraACLMapperTest.java     | 4 ++--
 4 files changed, 16 insertions(+), 8 deletions(-)

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 376cd0a..b04814c 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
@@ -112,8 +112,7 @@ public class CassandraACLMapper {
 
     public Mono<MailboxACL> getACL(CassandraId cassandraId) {
         return getStoredACLRow(cassandraId)
-            .map(row -> getAcl(cassandraId, row))
-            .defaultIfEmpty(MailboxACL.EMPTY);
+            .map(row -> getAcl(cassandraId, row));
     }
 
     private MailboxACL getAcl(CassandraId cassandraId, Row row) {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
index 05d3339..a0b4fd4 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
@@ -159,12 +159,17 @@ public class CassandraMailboxMapper implements MailboxMapper {
     }
 
     private Mono<Mailbox> retrieveMailbox(CassandraId mailboxId) {
-        Mono<MailboxACL> acl = cassandraACLMapper.getACL(mailboxId);
+        Mono<MailboxACL> acl = retrieveAcl(mailboxId);
         Mono<Mailbox> simpleMailbox = mailboxDAO.retrieveMailbox(mailboxId);
 
         return acl.zipWith(simpleMailbox, this::addAcl);
     }
 
+    private Mono<MailboxACL> retrieveAcl(CassandraId mailboxId) {
+        return cassandraACLMapper.getACL(mailboxId)
+            .defaultIfEmpty(MailboxACL.EMPTY);
+    }
+
     private Mailbox addAcl(MailboxACL acl, Mailbox mailbox) {
         mailbox.setACL(acl);
         return mailbox;
@@ -302,7 +307,7 @@ public class CassandraMailboxMapper implements MailboxMapper {
 
     private Mono<Mailbox> toMailboxWithAcl(Mailbox mailbox) {
         CassandraId cassandraId = (CassandraId) mailbox.getMailboxId();
-        return cassandraACLMapper.getACL(cassandraId)
+        return retrieveAcl(cassandraId)
             .map(acl -> {
                 mailbox.setACL(acl);
                 return mailbox;
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskRunner.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskRunner.java
index 794c2e6..8e7c6e0 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskRunner.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskRunner.java
@@ -89,8 +89,12 @@ public class MailboxMergingTaskRunner {
 
     private void mergeRights(CassandraId oldMailboxId, CassandraId newMailboxId) {
         try {
-            MailboxACL oldAcl = cassandraACLMapper.getACL(oldMailboxId).block();
-            MailboxACL newAcl = cassandraACLMapper.getACL(newMailboxId).block();
+            MailboxACL oldAcl = cassandraACLMapper.getACL(oldMailboxId)
+                .defaultIfEmpty(MailboxACL.EMPTY)
+                .block();
+            MailboxACL newAcl = cassandraACLMapper.getACL(newMailboxId)
+                .defaultIfEmpty(MailboxACL.EMPTY)
+                .block();
             MailboxACL finalAcl = newAcl.union(oldAcl);
 
             cassandraACLMapper.setACL(newMailboxId, finalAcl);
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/CassandraACLMapperTest.java
index d6dafc1..f3f8b81 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/CassandraACLMapperTest.java
@@ -85,7 +85,7 @@ class CassandraACLMapperTest {
 
     @Test
     void retrieveACLWhenNoACLStoredShouldReturnEmptyACL() {
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(MailboxACL.EMPTY);
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).blockOptional()).isEmpty();
     }
 
     @Test
@@ -98,7 +98,7 @@ class CassandraACLMapperTest {
 
         cassandraACLMapper.delete(MAILBOX_ID).block();
 
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(MailboxACL.EMPTY);
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).blockOptional()).isEmpty();
     }
 
     @Test


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


[james-project] 21/22: JAMES-3148 Readability enhencements: method rename and extraction

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 48daa66b16c1e62fd7cb4b2d3fb584dd9fdd787f
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 17 14:43:07 2020 +0700

    JAMES-3148 Readability enhencements: method rename and extraction
---
 .../mailbox/cassandra/DeleteMessageListener.java   | 46 +++++++++++++---------
 1 file changed, 27 insertions(+), 19 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index ce1a3ce..53b1d2e 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -123,12 +123,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
         if (event instanceof Expunged) {
             Expunged expunged = (Expunged) event;
 
-            Flux.fromIterable(expunged.getExpunged()
-                .values())
-                .map(MessageMetaData::getMessageId)
-                .map(CassandraMessageId.class::cast)
-                .concatMap(this::handleDeletion)
-                .then()
+            handleMessageDeletion(expunged)
                 .block();
         }
         if (event instanceof MailboxDeletion) {
@@ -136,28 +131,41 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
 
             CassandraId mailboxId = (CassandraId) mailboxDeletion.getMailboxId();
 
-            messageIdDAO.retrieveMessages(mailboxId, MessageRange.all())
-                .map(ComposedMessageIdWithMetaData::getComposedMessageId)
-                .concatMap(metadata -> handleDeletion((CassandraMessageId) metadata.getMessageId(), mailboxId)
-                    .then(imapUidDAO.delete((CassandraMessageId) metadata.getMessageId(), mailboxId))
-                    .then(messageIdDAO.delete(mailboxId, metadata.getUid())))
-                .then(deleteAcl(mailboxId))
-                .then(applicableFlagDAO.delete(mailboxId))
-                .then(firstUnseenDAO.removeAll(mailboxId))
-                .then(deletedMessageDAO.removeAll(mailboxId))
-                .then(counterDAO.delete(mailboxId))
-                .then(recentsDAO.delete(mailboxId))
+            handleMailboxDeletion(mailboxId)
                 .block();
         }
     }
 
+    private Mono<Void> handleMailboxDeletion(CassandraId mailboxId) {
+        return messageIdDAO.retrieveMessages(mailboxId, MessageRange.all())
+            .map(ComposedMessageIdWithMetaData::getComposedMessageId)
+            .concatMap(metadata -> handleMessageDeletionAsPartOfMailboxDeletion((CassandraMessageId) metadata.getMessageId(), mailboxId)
+                .then(imapUidDAO.delete((CassandraMessageId) metadata.getMessageId(), mailboxId))
+                .then(messageIdDAO.delete(mailboxId, metadata.getUid())))
+            .then(deleteAcl(mailboxId))
+            .then(applicableFlagDAO.delete(mailboxId))
+            .then(firstUnseenDAO.removeAll(mailboxId))
+            .then(deletedMessageDAO.removeAll(mailboxId))
+            .then(counterDAO.delete(mailboxId))
+            .then(recentsDAO.delete(mailboxId));
+    }
+
+    private Mono<Void> handleMessageDeletion(Expunged expunged) {
+        return Flux.fromIterable(expunged.getExpunged()
+            .values())
+            .map(MessageMetaData::getMessageId)
+            .map(CassandraMessageId.class::cast)
+            .concatMap(this::handleMessageDeletion)
+            .then();
+    }
+
     private Mono<Void> deleteAcl(CassandraId mailboxId) {
         return aclMapper.getACL(mailboxId)
             .flatMap(acl -> rightsDAO.update(mailboxId, ACLDiff.computeDiff(acl, MailboxACL.EMPTY)))
             .then(aclMapper.delete(mailboxId));
     }
 
-    private Mono<Void> handleDeletion(CassandraMessageId messageId) {
+    private Mono<Void> handleMessageDeletion(CassandraMessageId messageId) {
         return Mono.just(messageId)
             .filterWhen(this::isReferenced)
             .flatMap(id -> readMessage(id)
@@ -166,7 +174,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
                 .then(messageDAO.delete(messageId)));
     }
 
-    private Mono<Void> handleDeletion(CassandraMessageId messageId, CassandraId excludedId) {
+    private Mono<Void> handleMessageDeletionAsPartOfMailboxDeletion(CassandraMessageId messageId, CassandraId excludedId) {
         return Mono.just(messageId)
             .filterWhen(id -> isReferenced(id, excludedId))
             .flatMap(id -> readMessage(id)


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


[james-project] 03/22: JAMES-3148 [ADR] Cassandra metadata cleanup upon deletion

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 cb1380d41f97b85decf99d397bdcc35c849c6bcb
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 16:53:57 2020 +0700

    JAMES-3148 [ADR] Cassandra metadata cleanup upon deletion
---
 src/adr/0029-Cassandra-mailbox-deletion-cleanup.md | 44 ++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/src/adr/0029-Cassandra-mailbox-deletion-cleanup.md b/src/adr/0029-Cassandra-mailbox-deletion-cleanup.md
new file mode 100644
index 0000000..d97e3cd
--- /dev/null
+++ b/src/adr/0029-Cassandra-mailbox-deletion-cleanup.md
@@ -0,0 +1,44 @@
+# 29. Cassandra mailbox deletion cleanup
+
+Date: 2020-04-12
+
+## Status
+
+Accepted (lazy consensus)
+
+## Context
+
+Cassandra is used within distributed James product to hold messages and mailboxes metadata.
+
+Cassandra holds the following tables:
+ - mailboxPathV2 + mailbox allowing to retrieve mailboxes informations
+ - acl + UserMailboxACL hold denormalized information
+ - messageIdTable & imapUidTable allow to retrieve mailbox context information
+ - messageV2 table holds message metadata
+ - attachmentV2 holds attachments for messages
+ - References to these attachments are contained within the attachmentOwner and attachmentMessageId tables
+ 
+Currently, the deletion only deletes the first level of metadata. Lower level metadata stay unreachable. The data looks 
+deleted but references are actually still present.
+
+Concretely:
+ - Upon mailbox deletion, only mailboxPathV2 & mailbox content is deleted. messageIdTable, imapUidTable, messageV2, 
+ attachmentV2 & attachmentMessageId metadata are left undeleted.
+ - Upon mailbox deletion, acl + UserMailboxACL are not deleted.
+ - Upon message deletion, only messageIdTable & imapUidTable content are deleted. messageV2, attachmentV2 & 
+ attachmentMessageId metadata are left undeleted.
+
+This jeopardize efforts to regain disk space and privacy, for example through blobStore garbage collection.
+
+## Decision
+
+We need to cleanup Cassandra metadata. They can be retrieved from dandling metadata after the delete operation had been 
+conducted out. We need to delete the lower levels first so that upon failures undeleted metadata can still be reached.
+
+This cleanup is not needed for strict correctness from a MailboxManager point of view thus it could be carried out 
+asynchronously, via mailbox listeners so that it can be retried.
+
+## Consequences
+
+Mailbox listener failures lead to eventBus retrying their execution, we need to ensure the result of the deletion to be 
+idempotent. 
\ No newline at end of file


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


[james-project] 18/22: JAMES-3148 Cleanup Mailbox recents DAO

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 eb4633e51ee4fb205b24ccfb55ff87ed4274c0ef
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 21:04:07 2020 +0700

    JAMES-3148 Cleanup Mailbox recents DAO
---
 .../CassandraMailboxSessionMapperFactory.java      |  2 +-
 .../mailbox/cassandra/DeleteMessageListener.java   |  6 +++-
 .../cassandra/mail/CassandraMailboxRecentsDAO.java | 18 ++++++++++--
 .../cassandra/CassandraMailboxManagerTest.java     | 32 ++++++++++++++++++++++
 .../mail/CassandraMailboxRecentDAOTest.java        | 19 +++++++++++++
 5 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
index 3631d52..def8f71 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
@@ -206,6 +206,6 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa
     public DeleteMessageListener deleteMessageListener() {
         return new DeleteMessageListener(imapUidDAO, messageIdDAO, messageDAO, attachmentDAOV2, ownerDAO,
             attachmentMessageIdDAO, aclMapper, userMailboxRightsDAO, applicableFlagDAO, firstUnseenDAO, deletedMessageDAO,
-            mailboxCounterDAO);
+            mailboxCounterDAO, mailboxRecentsDAO);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index ed70a9a..521a59a 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -36,6 +36,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMailboxCounterDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMailboxRecentsDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
@@ -73,13 +74,14 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
     private final CassandraFirstUnseenDAO firstUnseenDAO;
     private final CassandraDeletedMessageDAO deletedMessageDAO;
     private final CassandraMailboxCounterDAO counterDAO;
+    private final CassandraMailboxRecentsDAO recentsDAO;
 
     @Inject
     public DeleteMessageListener(CassandraMessageIdToImapUidDAO imapUidDAO, CassandraMessageIdDAO messageIdDAO, CassandraMessageDAO messageDAO,
                                  CassandraAttachmentDAOV2 attachmentDAO, CassandraAttachmentOwnerDAO ownerDAO,
                                  CassandraAttachmentMessageIdDAO attachmentMessageIdDAO, CassandraACLMapper aclMapper,
                                  CassandraUserMailboxRightsDAO rightsDAO, CassandraApplicableFlagDAO applicableFlagDAO,
-                                 CassandraFirstUnseenDAO firstUnseenDAO, CassandraDeletedMessageDAO deletedMessageDAO, CassandraMailboxCounterDAO counterDAO) {
+                                 CassandraFirstUnseenDAO firstUnseenDAO, CassandraDeletedMessageDAO deletedMessageDAO, CassandraMailboxCounterDAO counterDAO, CassandraMailboxRecentsDAO recentsDAO) {
         this.imapUidDAO = imapUidDAO;
         this.messageIdDAO = messageIdDAO;
         this.messageDAO = messageDAO;
@@ -92,6 +94,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
         this.firstUnseenDAO = firstUnseenDAO;
         this.deletedMessageDAO = deletedMessageDAO;
         this.counterDAO = counterDAO;
+        this.recentsDAO = recentsDAO;
     }
 
     @Override
@@ -132,6 +135,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
                 .then(firstUnseenDAO.removeAll(mailboxId))
                 .then(deletedMessageDAO.removeAll(mailboxId))
                 .then(counterDAO.delete(mailboxId))
+                .then(recentsDAO.delete(mailboxId))
                 .block();
         }
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java
index 3d91975..ed96abd 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java
@@ -20,7 +20,6 @@
 package org.apache.james.mailbox.cassandra.mail;
 
 import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.delete;
 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;
@@ -36,6 +35,7 @@ import org.apache.james.mailbox.cassandra.table.CassandraMailboxRecentsTable;
 import com.datastax.driver.core.BoundStatement;
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
 import com.google.common.annotations.VisibleForTesting;
 
 import reactor.core.publisher.Flux;
@@ -46,6 +46,7 @@ public class CassandraMailboxRecentsDAO {
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
     private final PreparedStatement readStatement;
     private final PreparedStatement deleteStatement;
+    private final PreparedStatement deleteAllStatement;
     private final PreparedStatement addStatement;
     private CassandraUtils cassandraUtils;
 
@@ -54,6 +55,7 @@ public class CassandraMailboxRecentsDAO {
         cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
         readStatement = createReadStatement(session);
         deleteStatement = createDeleteStatement(session);
+        deleteAllStatement = createDeleteAllStatement(session);
         addStatement = createAddStatement(session);
         this.cassandraUtils = cassandraUtils;
     }
@@ -72,12 +74,19 @@ public class CassandraMailboxRecentsDAO {
 
     private PreparedStatement createDeleteStatement(Session session) {
         return session.prepare(
-            delete()
+            QueryBuilder.delete()
                 .from(CassandraMailboxRecentsTable.TABLE_NAME)
                 .where(eq(CassandraMailboxRecentsTable.MAILBOX_ID, bindMarker(CassandraMailboxRecentsTable.MAILBOX_ID)))
                 .and(eq(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID, bindMarker(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID))));
     }
 
+    private PreparedStatement createDeleteAllStatement(Session session) {
+        return session.prepare(
+            QueryBuilder.delete()
+                .from(CassandraMailboxRecentsTable.TABLE_NAME)
+                .where(eq(CassandraMailboxRecentsTable.MAILBOX_ID, bindMarker(CassandraMailboxRecentsTable.MAILBOX_ID))));
+    }
+
     private PreparedStatement createAddStatement(Session session) {
         return session.prepare(
             insertInto(CassandraMailboxRecentsTable.TABLE_NAME)
@@ -103,6 +112,11 @@ public class CassandraMailboxRecentsDAO {
             .setLong(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID, messageUid.asLong()));
     }
 
+    public Mono<Void> delete(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeVoid(deleteAllStatement.bind()
+            .setUUID(CassandraMailboxRecentsTable.MAILBOX_ID, mailboxId.asUuid()));
+    }
+
     public Mono<Void> addToRecent(CassandraId mailboxId, MessageUid messageUid) {
         return cassandraAsyncExecutor.executeVoid(addStatement.bind()
             .setUUID(CassandraMailboxRecentsTable.MAILBOX_ID, mailboxId.asUuid())
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 36ca5d8..0865d83 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
@@ -48,6 +48,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMailboxCounterDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMailboxRecentsDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
@@ -702,6 +703,37 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
                 .isEmpty();
         }
 
+        @Test
+        void deleteMailboxShouldCleanUpRecent(CassandraCluster cassandraCluster) throws Exception {
+            inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .withFlags(new Flags(Flags.Flag.RECENT))
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            assertThat(new CassandraMailboxRecentsDAO(cassandraCluster.getConf()).getRecentMessageUidsInMailbox((CassandraId) inboxId)
+                .collectList().block())
+                .isEmpty();
+        }
+
+        @Test
+        void deleteMailboxShouldCleanUpRecentWhenFailure(CassandraCluster cassandraCluster) throws Exception {
+            inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .withFlags(new Flags(Flags.Flag.RECENT))
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM mailboxRecents WHERE mailboxId=:mailboxId;"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            assertThat(new CassandraMailboxRecentsDAO(cassandraCluster.getConf()).getRecentMessageUidsInMailbox((CassandraId) inboxId)
+                .collectList().block())
+                .isEmpty();
+        }
+
         private CassandraMailboxCounterDAO countersDAO(CassandraCluster cassandraCluster) {
             return new CassandraMailboxCounterDAO(cassandraCluster.getConf());
         }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentDAOTest.java
index 8e05300..e773083 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentDAOTest.java
@@ -20,6 +20,7 @@
 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.stream.IntStream;
 
@@ -78,6 +79,24 @@ class CassandraMailboxRecentDAOTest {
     }
 
     @Test
+    void getRecentMessageUidsInMailboxShouldNotReturnDeletedItems() {
+        testee.addToRecent(CASSANDRA_ID, UID1).block();
+        testee.addToRecent(CASSANDRA_ID, UID2).block();
+
+        testee.delete(CASSANDRA_ID).block();
+
+        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
+            .collectList()
+            .block())
+            .isEmpty();
+    }
+
+    @Test
+    void deleteShouldNotThrowWhenNothing() {
+        assertThatCode(() -> testee.delete(CASSANDRA_ID).block()).doesNotThrowAnyException();
+    }
+
+    @Test
     void removeFromRecentShouldNotFailIfNotExisting() {
         testee.removeFromRecent(CASSANDRA_ID, UID1).block();
 


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


[james-project] 09/22: JAMES-3148 Also cleanup AttachmentMessageIdDAO upon deletion

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 3098849c55f58bc70e1cf7c2864aba88b7ce0d4d
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 15:46:50 2020 +0700

    JAMES-3148 Also cleanup AttachmentMessageIdDAO upon deletion
---
 .../mailbox/cassandra/DeleteMessageListener.java   |  9 +++++-
 .../mail/CassandraAttachmentMessageIdDAO.java      | 18 +++++++++++
 .../cassandra/CassandraMailboxManagerTest.java     | 25 ++++++++++++++-
 .../mail/CassandraAttachmentMessageIdDAOTest.java  | 37 ++++++++++++++++++++++
 4 files changed, 87 insertions(+), 2 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index 15d7b35..31529e6 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -114,7 +114,8 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
         return Mono.just(messageId)
             .filterWhen(this::isReferenced)
             .flatMap(id -> readMessage(id)
-                .flatMap(this::deleteUnreferencedAttachments)
+                .flatMap(message -> deleteUnreferencedAttachments(message).thenReturn(message))
+                .flatMap(this::deleteAttachmentMessageIds)
                 .then(messageDAO.delete(messageId)));
     }
 
@@ -130,6 +131,12 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
             .then();
     }
 
+    private Mono<Void> deleteAttachmentMessageIds(MessageRepresentation message) {
+        return Flux.fromIterable(message.getAttachments())
+            .concatMap(attachment -> attachmentMessageIdDAO.delete(attachment.getAttachmentId(), message.getMessageId()))
+            .then();
+    }
+
     private Mono<Boolean> hasOtherMessagesReferences(MessageRepresentation message, MessageAttachmentRepresentation attachment) {
         return attachmentMessageIdDAO.getOwnerMessageIds(attachment.getAttachmentId())
             .filter(messageId -> !message.getMessageId().equals(messageId))
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java
index 8488472..12682c2 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java
@@ -38,6 +38,7 @@ import org.apache.james.mailbox.model.MessageId;
 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.google.common.base.Preconditions;
 
 import reactor.core.publisher.Flux;
@@ -48,6 +49,7 @@ public class CassandraAttachmentMessageIdDAO {
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
     private final PreparedStatement insertStatement;
     private final PreparedStatement selectStatement;
+    private final PreparedStatement deleteStatement;
     private final MessageId.Factory messageIdFactory;
 
     @Inject
@@ -57,6 +59,7 @@ public class CassandraAttachmentMessageIdDAO {
 
         this.selectStatement = prepareSelect(session);
         this.insertStatement = prepareInsert(session);
+        this.deleteStatement = prepareDelete(session);
     }
 
     private PreparedStatement prepareInsert(Session session) {
@@ -67,6 +70,14 @@ public class CassandraAttachmentMessageIdDAO {
                 .value(MESSAGE_ID, bindMarker(MESSAGE_ID)));
     }
 
+    private PreparedStatement prepareDelete(Session session) {
+        return session.prepare(
+            QueryBuilder.delete()
+                .from(TABLE_NAME)
+                .where(eq(ATTACHMENT_ID_AS_UUID, bindMarker(ATTACHMENT_ID_AS_UUID)))
+                .and(eq(MESSAGE_ID, bindMarker(MESSAGE_ID))));
+    }
+
     private PreparedStatement prepareSelect(Session session) {
         return session.prepare(select(FIELDS)
             .from(TABLE_NAME)
@@ -92,4 +103,11 @@ public class CassandraAttachmentMessageIdDAO {
                 .setString(ATTACHMENT_ID, attachmentId.getId())
                 .setString(MESSAGE_ID, ownerMessageId.serialize()));
     }
+
+    public Mono<Void> delete(AttachmentId attachmentId, MessageId ownerMessageId) {
+        return cassandraAsyncExecutor.executeVoid(
+            deleteStatement.bind()
+                .setUUID(ATTACHMENT_ID_AS_UUID, attachmentId.asUUID())
+                .setString(MESSAGE_ID, ownerMessageId.serialize()));
+    }
 }
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 55eeb7c..3f427a3 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
@@ -34,6 +34,7 @@ import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
+import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
@@ -128,9 +129,13 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
                 softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
                     .isEmpty();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .doesNotContain(cassandraMessageId);
             });
         }
 
+
         @Test
         void deleteShouldUnreferenceMessageMetadata(CassandraCluster cassandraCluster) throws Exception {
             ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
@@ -153,6 +158,9 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
                 softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
                     .isEmpty();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .doesNotContain(cassandraMessageId);
             });
         }
 
@@ -187,6 +195,9 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
                 softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
                     .isPresent();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .contains(cassandraMessageId);
             });
         }
 
@@ -214,6 +225,9 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
                 softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
                     .isPresent();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .contains(cassandraMessageId);
             });
         }
 
@@ -248,6 +262,9 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
                 softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
                     .isPresent();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .doesNotContain(cassandraMessageId);
             });
         }
 
@@ -269,16 +286,22 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
             SoftAssertions.assertSoftly(softly -> {
                 CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
-                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
 
                 softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
                     .isPresent();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .doesNotContain(cassandraMessageId);
             });
         }
 
+        private CassandraAttachmentMessageIdDAO attachmentMessageIdDAO(CassandraCluster cassandraCluster) {
+            return new CassandraAttachmentMessageIdDAO(cassandraCluster.getConf(), new CassandraMessageId.Factory());
+        }
+
         private CassandraAttachmentDAOV2 attachmentDAO(CassandraCluster cassandraCluster) {
             return new CassandraAttachmentDAOV2(new HashBlobId.Factory(), cassandraCluster.getConf());
         }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAOTest.java
index d7aff6e..271620c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAOTest.java
@@ -20,6 +20,7 @@
 package org.apache.james.mailbox.cassandra.mail;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
@@ -63,4 +64,40 @@ class CassandraAttachmentMessageIdDAOTest {
             .containsExactlyInAnyOrder(messageId1, messageId2)
             .hasSize(2);
     }
+
+    @Test
+    void getOwnerMessageIdsShouldNotReturnDeletedValues() {
+        CassandraMessageId messageId1 = new CassandraMessageId.Factory().generate();
+        AttachmentId attachmentId = AttachmentId.random();
+
+        testee.storeAttachmentForMessageId(attachmentId, messageId1).block();
+
+        testee.delete(attachmentId, messageId1).block();
+        assertThat(testee.getOwnerMessageIds(attachmentId).collectList().block())
+            .isEmpty();
+    }
+
+    @Test
+    void deleteShouldOnlyDeleteSuppliedValues() {
+        CassandraMessageId messageId1 = new CassandraMessageId.Factory().generate();
+        CassandraMessageId messageId2 = new CassandraMessageId.Factory().generate();
+        AttachmentId attachmentId = AttachmentId.random();
+
+        testee.storeAttachmentForMessageId(attachmentId, messageId1).block();
+        testee.storeAttachmentForMessageId(attachmentId, messageId2).block();
+
+        testee.delete(attachmentId, messageId1).block();
+
+        assertThat(testee.getOwnerMessageIds(attachmentId).collectList().block())
+            .containsExactly(messageId2);
+    }
+
+    @Test
+    void deleteShouldNotThrowWhenNotExisting() {
+        CassandraMessageId messageId1 = new CassandraMessageId.Factory().generate();
+        AttachmentId attachmentId = AttachmentId.random();
+
+        assertThatCode(() -> testee.delete(attachmentId, messageId1).block())
+            .doesNotThrowAnyException();
+    }
 }
\ No newline at end of file


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


[james-project] 15/22: JAMES-3148 Cleanup First Unseen DAO

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 05bd2f6a8620d64114ab3a0f4518c266c6fd6053
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 20:36:49 2020 +0700

    JAMES-3148 Cleanup First Unseen DAO
---
 .../CassandraMailboxSessionMapperFactory.java      |  2 +-
 .../mailbox/cassandra/DeleteMessageListener.java   |  8 +++++-
 .../cassandra/mail/CassandraFirstUnseenDAO.java    | 13 +++++++++
 .../cassandra/CassandraMailboxManagerTest.java     | 33 ++++++++++++++++++++++
 .../mail/CassandraFirstUnseenDAOTest.java          | 27 ++++++++++++++++++
 5 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
index 62ccb3a..13a6d95 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
@@ -205,6 +205,6 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa
 
     public DeleteMessageListener deleteMessageListener() {
         return new DeleteMessageListener(imapUidDAO, messageIdDAO, messageDAO, attachmentDAOV2, ownerDAO,
-            attachmentMessageIdDAO, aclMapper, userMailboxRightsDAO, applicableFlagDAO);
+            attachmentMessageIdDAO, aclMapper, userMailboxRightsDAO, applicableFlagDAO, firstUnseenDAO);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index c4de8cc..7c24b4e 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -33,6 +33,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
@@ -67,11 +68,14 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
     private final CassandraACLMapper aclMapper;
     private final CassandraUserMailboxRightsDAO rightsDAO;
     private final CassandraApplicableFlagDAO applicableFlagDAO;
+    private final CassandraFirstUnseenDAO firstUnseenDAO;
 
     @Inject
     public DeleteMessageListener(CassandraMessageIdToImapUidDAO imapUidDAO, CassandraMessageIdDAO messageIdDAO, CassandraMessageDAO messageDAO,
                                  CassandraAttachmentDAOV2 attachmentDAO, CassandraAttachmentOwnerDAO ownerDAO,
-                                 CassandraAttachmentMessageIdDAO attachmentMessageIdDAO, CassandraACLMapper aclMapper, CassandraUserMailboxRightsDAO rightsDAO, CassandraApplicableFlagDAO applicableFlagDAO) {
+                                 CassandraAttachmentMessageIdDAO attachmentMessageIdDAO, CassandraACLMapper aclMapper,
+                                 CassandraUserMailboxRightsDAO rightsDAO, CassandraApplicableFlagDAO applicableFlagDAO,
+                                 CassandraFirstUnseenDAO firstUnseenDAO) {
         this.imapUidDAO = imapUidDAO;
         this.messageIdDAO = messageIdDAO;
         this.messageDAO = messageDAO;
@@ -81,6 +85,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
         this.aclMapper = aclMapper;
         this.rightsDAO = rightsDAO;
         this.applicableFlagDAO = applicableFlagDAO;
+        this.firstUnseenDAO = firstUnseenDAO;
     }
 
     @Override
@@ -118,6 +123,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
                     .then(messageIdDAO.delete(mailboxId, metadata.getUid())))
                 .then(deleteAcl(mailboxId))
                 .then(applicableFlagDAO.delete(mailboxId))
+                .then(firstUnseenDAO.removeAll(mailboxId))
                 .block();
         }
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java
index 94fc03b..d3fffc2 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java
@@ -44,6 +44,7 @@ public class CassandraFirstUnseenDAO {
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
     private final PreparedStatement addStatement;
     private final PreparedStatement deleteStatement;
+    private final PreparedStatement deleteAllStatement;
     private final PreparedStatement readStatement;
 
     @Inject
@@ -51,6 +52,7 @@ public class CassandraFirstUnseenDAO {
         this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
         this.addStatement = prepareAddStatement(session);
         this.deleteStatement = prepareDeleteStatement(session);
+        this.deleteAllStatement = prepareDeleteAllStatement(session);
         this.readStatement = prepareReadStatement(session);
     }
 
@@ -69,6 +71,12 @@ public class CassandraFirstUnseenDAO {
             .and(eq(UID, bindMarker(UID))));
     }
 
+    private PreparedStatement prepareDeleteAllStatement(Session session) {
+        return session.prepare(delete()
+            .from(TABLE_NAME)
+            .where(eq(MAILBOX_ID, bindMarker(MAILBOX_ID))));
+    }
+
     private PreparedStatement prepareAddStatement(Session session) {
         return session.prepare(insertInto(TABLE_NAME)
             .value(MAILBOX_ID, bindMarker(MAILBOX_ID))
@@ -88,6 +96,11 @@ public class CassandraFirstUnseenDAO {
             .setLong(UID, uid.asLong()));
     }
 
+    public Mono<Void> removeAll(CassandraId cassandraId) {
+        return cassandraAsyncExecutor.executeVoid(deleteAllStatement.bind()
+            .setUUID(MAILBOX_ID, cassandraId.asUuid()));
+    }
+
     public Mono<MessageUid> retrieveFirstUnread(CassandraId cassandraId) {
         return cassandraAsyncExecutor.executeSingleRow(
             readStatement.bind()
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 de77b65..56d9221 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
@@ -45,6 +45,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
@@ -613,6 +614,38 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
                 .isEmpty();
         }
 
+        @Test
+        void deleteMailboxShouldCleanUpFirstUnseenWhenFail(CassandraCluster cassandraCluster) throws Exception {
+            inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .withFlags(new Flags())
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            assertThat(firstUnseenDAO(cassandraCluster).retrieveFirstUnread((CassandraId) inboxId).blockOptional())
+                .isEmpty();
+        }
+
+        @Test
+        void deleteMailboxShouldCleanUpFirstUnseen(CassandraCluster cassandraCluster) throws Exception {
+            inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .withFlags(new Flags())
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM firstUnseen WHERE mailboxId=:mailboxId;"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            assertThat(firstUnseenDAO(cassandraCluster).retrieveFirstUnread((CassandraId) inboxId).blockOptional())
+                .isEmpty();
+        }
+
+        private CassandraFirstUnseenDAO firstUnseenDAO(CassandraCluster cassandraCluster) {
+            return new CassandraFirstUnseenDAO(cassandraCluster.getConf());
+        }
+
         private CassandraApplicableFlagDAO applicableFlagDAO(CassandraCluster cassandraCluster) {
             return new CassandraApplicableFlagDAO(cassandraCluster.getConf());
         }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAOTest.java
index 882ed3c..f9f54aa 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAOTest.java
@@ -20,6 +20,7 @@
 package org.apache.james.mailbox.cassandra.mail;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
@@ -60,6 +61,32 @@ class CassandraFirstUnseenDAOTest {
     }
 
     @Test
+    void addUnreadShouldNotReturnRemovedEntries() {
+        testee.addUnread(MAILBOX_ID, UID_1).block();
+
+        testee.removeAll(MAILBOX_ID).block();
+
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).blockOptional())
+            .isEmpty();
+    }
+
+    @Test
+    void removeAllShouldDeleteAllUidEntries() {
+        testee.addUnread(MAILBOX_ID, UID_1).block();
+        testee.addUnread(MAILBOX_ID, UID_2).block();
+
+        testee.removeAll(MAILBOX_ID).block();
+
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).blockOptional())
+            .isEmpty();
+    }
+
+    @Test
+    void removeAllShouldNotThrowWhenAbsent() {
+        assertThatCode(() -> testee.removeAll(MAILBOX_ID).block()).doesNotThrowAnyException();
+    }
+
+    @Test
     void retrieveFirstUnreadShouldReturnLowestUnreadUid() {
         testee.addUnread(MAILBOX_ID, UID_1).block();
 


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


[james-project] 07/22: JAMES-3148 CassandraMessageDAO::delete

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 485972262379590327ad71796a523b06bbcc6647
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 14:12:21 2020 +0700

    JAMES-3148 CassandraMessageDAO::delete
---
 .../apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java
index ff3ddfe..6659868 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java
@@ -142,7 +142,7 @@ public class CassandraAttachmentDAOV2 {
     private PreparedStatement prepareDelete(Session session) {
         return session.prepare(
             QueryBuilder.delete().from(TABLE_NAME)
-                .where(eq(ID, bindMarker(ID))));
+                .where(eq(ID_AS_UUID, bindMarker(ID_AS_UUID))));
     }
 
     private PreparedStatement prepareInsert(Session session) {


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


[james-project] 01/22: JAMES-3140 Add a way of parsing Size units

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 e1e8c1234327da80a7dc22f5a0ddc11f1e4c0475
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Apr 28 08:42:20 2020 +0700

    JAMES-3140 Add a way of parsing Size units
    
    Reuse amount/unit separation of DurationParser.
---
 .../java/org/apache/james/util/DurationParser.java | 35 ++----------
 .../java/org/apache/james/util/SizeFormat.java     | 25 ++++++++-
 .../java/org/apache/james/util/UnitParser.java     | 64 ++++++++++++++++++++++
 .../java/org/apache/james/util/SizeFormatTest.java | 60 ++++++++++++++++++++
 4 files changed, 153 insertions(+), 31 deletions(-)

diff --git a/server/container/util/src/main/java/org/apache/james/util/DurationParser.java b/server/container/util/src/main/java/org/apache/james/util/DurationParser.java
index a0d61a6..6194501 100644
--- a/server/container/util/src/main/java/org/apache/james/util/DurationParser.java
+++ b/server/container/util/src/main/java/org/apache/james/util/DurationParser.java
@@ -23,22 +23,11 @@ import java.time.temporal.ChronoUnit;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
-import java.util.Optional;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 
 public class DurationParser {
-
-    private static final String PATTERN_STRING = "\\s*(-?[0-9]+)\\s*([a-z,A-Z]*)\\s*";
-    private static final int AMOUNT = 1;
-    private static final int UNIT = 2;
-
-    private static Pattern PATTERN = Pattern.compile(PATTERN_STRING);
-
     private enum Unit {
         MILLI_SECONDS(ImmutableList.of("ms", "msec", "msecs"), ChronoUnit.MILLIS),
         SECONDS(ImmutableList.of("s", "sec", "secs", "second", "seconds"), ChronoUnit.SECONDS),
@@ -86,18 +75,11 @@ public class DurationParser {
     }
 
     public static Duration parse(String rawString, ChronoUnit defaultUnit) throws NumberFormatException {
-        Matcher res = PATTERN.matcher(rawString);
-        if (res.matches()) {
-            String unitAsString = res.group(UNIT);
-            String amountAsString = res.group(AMOUNT);
-            if (amountAsString != null && unitAsString != null) {
-                long time = Integer.parseInt(res.group(AMOUNT).trim());
-                Duration unitAsDuration = parseUnitAsDuration(unitAsString).orElse(defaultUnit.getDuration());
-
-                return computeDuration(unitAsDuration, time);
-            }
-        }
-        throw new NumberFormatException("The supplied String is not a supported format " + rawString);
+        UnitParser.ParsingResult parsingResult = UnitParser.parse(rawString);
+        Duration unitAsDuration = parsingResult.getUnit()
+            .map(s -> Unit.parse(s).getDuration())
+            .orElse(defaultUnit.getDuration());
+        return computeDuration(unitAsDuration, parsingResult.getNumber());
     }
 
     private static Duration computeDuration(Duration unitAsDuration, long time) {
@@ -105,11 +87,4 @@ public class DurationParser {
 
         return unitAsDuration.multipliedBy(time);
     }
-
-    private static Optional<Duration> parseUnitAsDuration(String unit) {
-        if (Strings.isNullOrEmpty(unit)) {
-            return Optional.empty();
-        }
-        return Optional.of(Unit.parse(unit).getDuration());
-    }
 }
diff --git a/server/container/util/src/main/java/org/apache/james/util/SizeFormat.java b/server/container/util/src/main/java/org/apache/james/util/SizeFormat.java
index c5293a8..c71ad3c 100644
--- a/server/container/util/src/main/java/org/apache/james/util/SizeFormat.java
+++ b/server/container/util/src/main/java/org/apache/james/util/SizeFormat.java
@@ -24,7 +24,9 @@ import java.math.BigInteger;
 import java.math.RoundingMode;
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
+import java.util.Arrays;
 import java.util.Locale;
+import java.util.Optional;
 
 import org.apache.commons.io.FileUtils;
 
@@ -59,6 +61,12 @@ public class SizeFormat {
         private static final DecimalFormatSymbols DECIMAL_FORMAT_SYMBOLS = new DecimalFormatSymbols(Locale.US);
         private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.##", DECIMAL_FORMAT_SYMBOLS);
 
+        public static Optional<Unit> of(String rawValue) {
+            return Arrays.stream(values())
+                .filter(unit -> unit.notation.equals(rawValue))
+                .findAny();
+        }
+
         private final BigInteger bytesCount;
         private final String notation;
 
@@ -67,6 +75,11 @@ public class SizeFormat {
             this.notation = notation;
         }
 
+        public long toByteCount(long value) {
+            return bytesCount.multiply(BigInteger.valueOf(value))
+                .longValueExact();
+        }
+
         public String format(long size) {
             return format(new BigDecimal(size));
         }
@@ -76,7 +89,7 @@ public class SizeFormat {
         }
 
         public BigDecimal scaleToUnit(BigDecimal sizeAsDecimal) {
-            return sizeAsDecimal.divide(new BigDecimal((bytesCount)), SCALE, RoundingMode.FLOOR);
+            return sizeAsDecimal.divide(new BigDecimal(bytesCount), SCALE, RoundingMode.FLOOR);
         }
 
         private String asString(BigDecimal bigDecimal) {
@@ -90,4 +103,14 @@ public class SizeFormat {
         return Unit.locateUnit(bytesCount)
             .format(bytesCount);
     }
+
+    public static long parseAsByteCount(String bytesWithUnit) {
+        UnitParser.ParsingResult parsingResult = UnitParser.parse(bytesWithUnit);
+        Unit unit = parsingResult.getUnit()
+            .map(rawValue -> Unit.of(rawValue)
+                .orElseThrow(() -> new IllegalArgumentException("Unknown unit " + rawValue)))
+            .orElse(Unit.Byte);
+
+        return unit.toByteCount(parsingResult.getNumber());
+    }
 }
diff --git a/server/container/util/src/main/java/org/apache/james/util/UnitParser.java b/server/container/util/src/main/java/org/apache/james/util/UnitParser.java
new file mode 100644
index 0000000..2f6e7d7
--- /dev/null
+++ b/server/container/util/src/main/java/org/apache/james/util/UnitParser.java
@@ -0,0 +1,64 @@
+/****************************************************************
+ * 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.util;
+
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.google.common.base.Strings;
+
+class UnitParser {
+    static class ParsingResult {
+        private final long number;
+        private final Optional<String> unit;
+
+        ParsingResult(long number, Optional<String> unit) {
+            this.number = number;
+            this.unit = unit;
+        }
+
+        public long getNumber() {
+            return number;
+        }
+
+        public Optional<String> getUnit() {
+            return unit;
+        }
+    }
+
+    private static final String PATTERN_STRING = "\\s*(-?[0-9]+)\\s*([a-z,A-Z]*)\\s*";
+    private static final int AMOUNT = 1;
+    private static final int UNIT = 2;
+
+    private static Pattern PATTERN = Pattern.compile(PATTERN_STRING);
+
+    static ParsingResult parse(String rawString) throws NumberFormatException {
+        Matcher res = PATTERN.matcher(rawString);
+        if (res.matches()) {
+            String unitAsString = res.group(UNIT);
+            String amountAsString = res.group(AMOUNT);
+            long amount = Integer.parseInt(amountAsString.trim());
+
+            return new ParsingResult(amount, Optional.of(unitAsString).filter(s -> !Strings.isNullOrEmpty(s)));
+        }
+        throw new NumberFormatException("Supplied value do not follow the unit format (number optionally suffixed with a string representing the unit");
+    }
+}
diff --git a/server/container/util/src/test/java/org/apache/james/util/SizeFormatTest.java b/server/container/util/src/test/java/org/apache/james/util/SizeFormatTest.java
index 03c5a24..436e0c5 100644
--- a/server/container/util/src/test/java/org/apache/james/util/SizeFormatTest.java
+++ b/server/container/util/src/test/java/org/apache/james/util/SizeFormatTest.java
@@ -86,4 +86,64 @@ class SizeFormatTest {
             .isEqualTo("1 TiB");
     }
 
+    @Test
+    void parseAsByteCountShouldReturnCountWhenNoUnit() {
+        assertThat(SizeFormat.parseAsByteCount("36"))
+            .isEqualTo(36);
+    }
+
+    @Test
+    void parseAsByteCountShouldAcceptKiB() {
+        assertThat(SizeFormat.parseAsByteCount("36 KiB"))
+            .isEqualTo(36 * 1024);
+    }
+
+    @Test
+    void parseAsByteCountShouldAcceptZero() {
+        assertThat(SizeFormat.parseAsByteCount("0 KiB"))
+            .isEqualTo(0);
+    }
+
+    @Test
+    void parseAsByteCountShouldThrowOnInvalidUnit() {
+        assertThatThrownBy(() -> SizeFormat.parseAsByteCount("0 invalid"))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    void parseAsByteCountShouldThrowOnMissingAmount() {
+        assertThatThrownBy(() -> SizeFormat.parseAsByteCount("KiB"))
+            .isInstanceOf(NumberFormatException.class);
+    }
+
+    @Test
+    void parseAsByteCountShouldThrowWhenEmpty() {
+        assertThatThrownBy(() -> SizeFormat.parseAsByteCount(""))
+            .isInstanceOf(NumberFormatException.class);
+    }
+
+    @Test
+    void parseAsByteCountShouldThrowWhenUnitDoesNotMatchCase() {
+        assertThatThrownBy(() -> SizeFormat.parseAsByteCount("12 KIB"))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    void parseAsByteCountShouldAcceptNegativeValue() {
+        assertThat(SizeFormat.parseAsByteCount("-36 KiB"))
+            .isEqualTo(-36 * 1024);
+    }
+
+    @Test
+    void parseAsByteCountShouldAcceptMiB() {
+        assertThat(SizeFormat.parseAsByteCount("36 MiB"))
+            .isEqualTo(36 * 1024 * 1024);
+    }
+
+    @Test
+    void parseAsByteCountShouldAcceptGiB() {
+        assertThat(SizeFormat.parseAsByteCount("36 GiB"))
+            .isEqualTo(36L * 1024L * 1024L * 1024L);
+    }
+
 }


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


[james-project] 04/22: JAMES-3148 FunctionalUtils negate helper

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 30d97458200dfda7cba52d42ca63ab9401e1de82
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 12:55:09 2020 +0700

    JAMES-3148 FunctionalUtils negate helper
---
 .../util/src/main/java/org/apache/james/util/FunctionalUtils.java    | 5 +++++
 .../java/org/apache/james/jmap/http/DefaultMailboxesProvisioner.java | 4 +++-
 .../james/queue/rabbitmq/view/cassandra/CassandraMailQueueView.java  | 4 +++-
 .../apache/james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java  | 3 ++-
 4 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/server/container/util/src/main/java/org/apache/james/util/FunctionalUtils.java b/server/container/util/src/main/java/org/apache/james/util/FunctionalUtils.java
index 30c0b63..5a06060 100644
--- a/server/container/util/src/main/java/org/apache/james/util/FunctionalUtils.java
+++ b/server/container/util/src/main/java/org/apache/james/util/FunctionalUtils.java
@@ -19,6 +19,7 @@
 package org.apache.james.util;
 
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.UnaryOperator;
 
@@ -37,6 +38,10 @@ public class FunctionalUtils {
         };
     }
 
+    public static Function<Boolean, Boolean> negate() {
+        return b -> !b;
+    }
+
     public static Predicate<Boolean> identityPredicate() {
         return b -> b;
     }
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/DefaultMailboxesProvisioner.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/DefaultMailboxesProvisioner.java
index a93c5ad..3252e95 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/DefaultMailboxesProvisioner.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/DefaultMailboxesProvisioner.java
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.james.jmap.http;
 
+import static org.apache.james.util.FunctionalUtils.negate;
+
 import java.util.Optional;
 import java.util.function.Function;
 
@@ -80,7 +82,7 @@ class DefaultMailboxesProvisioner {
     private Mono<Boolean> mailboxDoesntExist(MailboxPath mailboxPath, MailboxSession session) {
         try {
             return Mono.from(mailboxManager.mailboxExists(mailboxPath, session))
-                .map(x -> !x);
+                .map(negate());
         } catch (MailboxException e) {
             throw new RuntimeException(e);
         }
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueView.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueView.java
index 0c5af4c..aede929 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueView.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/CassandraMailQueueView.java
@@ -19,6 +19,8 @@
 
 package org.apache.james.queue.rabbitmq.view.cassandra;
 
+import static org.apache.james.util.FunctionalUtils.negate;
+
 import javax.inject.Inject;
 
 import org.apache.james.queue.api.ManageableMailQueue;
@@ -125,6 +127,6 @@ public class CassandraMailQueueView implements MailQueueView {
     @Override
     public Mono<Boolean> isPresent(EnqueueId id) {
         return cassandraMailQueueMailDelete.isDeleted(id, mailQueueName)
-                .map(bool -> !bool);
+                .map(negate());
     }
 }
diff --git a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java
index a0551e9..1594d87 100644
--- a/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java
+++ b/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java
@@ -26,6 +26,7 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
 import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.DeletedMailTable.ENQUEUE_ID;
 import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.DeletedMailTable.QUEUE_NAME;
 import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.DeletedMailTable.TABLE_NAME;
+import static org.apache.james.util.FunctionalUtils.negate;
 
 import javax.inject.Inject;
 
@@ -79,6 +80,6 @@ public class DeletedMailsDAO {
 
     Mono<Boolean> isStillEnqueued(MailQueueName mailQueueName, EnqueueId enqueueId) {
         return isDeleted(mailQueueName, enqueueId)
-            .map(b -> !b);
+            .map(negate());
     }
 }


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


[james-project] 11/22: JAMES-3148 ACL deletion

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 5bddcdc09f983384699bb8cdf54d0dd5d286ef5e
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 16:45:09 2020 +0700

    JAMES-3148 ACL deletion
---
 .../mailbox/cassandra/mail/CassandraACLMapper.java   | 16 ++++++++++++++++
 .../cassandra/mail/CassandraACLMapperTest.java       | 20 ++++++++++++++++++++
 2 files changed, 36 insertions(+)

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 43eeef8..376cd0a 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
@@ -49,6 +49,7 @@ 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;
@@ -64,6 +65,7 @@ public class CassandraACLMapper {
     private final PreparedStatement conditionalInsertStatement;
     private final PreparedStatement conditionalUpdateStatement;
     private final PreparedStatement readStatement;
+    private final PreparedStatement deleteStatement;
 
     @Inject
     public CassandraACLMapper(Session session, CassandraUserMailboxRightsDAO userMailboxRightsDAO, CassandraConfiguration cassandraConfiguration) {
@@ -72,9 +74,17 @@ public class CassandraACLMapper {
         this.conditionalInsertStatement = prepareConditionalInsert(session);
         this.conditionalUpdateStatement = prepareConditionalUpdate(session);
         this.readStatement = prepareReadStatement(session);
+        this.deleteStatement = prepareDelete(session);
         this.userMailboxRightsDAO = userMailboxRightsDAO;
     }
 
+    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)
@@ -157,6 +167,12 @@ public class CassandraACLMapper {
             .map(any -> aclWithVersion.mailboxACL);
     }
 
+    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()
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/CassandraACLMapperTest.java
index d6b66e9..d6dafc1 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/CassandraACLMapperTest.java
@@ -21,6 +21,7 @@ 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;
@@ -88,6 +89,25 @@ class CassandraACLMapperTest {
     }
 
     @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).block()).isEqualTo(MailboxACL.EMPTY);
+    }
+
+    @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);


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


[james-project] 17/22: JAMES-3148 Cleanup MailboxCounters DAO

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 1df0a9f47a2fc68db2e9f39309f5c26efaa5fdfa
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 20:56:22 2020 +0700

    JAMES-3148 Cleanup MailboxCounters DAO
---
 .../CassandraMailboxSessionMapperFactory.java      |  3 +-
 .../mailbox/cassandra/DeleteMessageListener.java   |  6 +++-
 .../cassandra/mail/CassandraMailboxCounterDAO.java |  8 ++++++
 .../cassandra/CassandraMailboxManagerTest.java     | 33 ++++++++++++++++++++++
 .../mail/CassandraMailboxCounterDAOTest.java       | 17 +++++++++++
 5 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
index ba80ed4..3631d52 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
@@ -205,6 +205,7 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa
 
     public DeleteMessageListener deleteMessageListener() {
         return new DeleteMessageListener(imapUidDAO, messageIdDAO, messageDAO, attachmentDAOV2, ownerDAO,
-            attachmentMessageIdDAO, aclMapper, userMailboxRightsDAO, applicableFlagDAO, firstUnseenDAO, deletedMessageDAO);
+            attachmentMessageIdDAO, aclMapper, userMailboxRightsDAO, applicableFlagDAO, firstUnseenDAO, deletedMessageDAO,
+            mailboxCounterDAO);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index c0f74d9..ed70a9a 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -35,6 +35,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMailboxCounterDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
@@ -71,13 +72,14 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
     private final CassandraApplicableFlagDAO applicableFlagDAO;
     private final CassandraFirstUnseenDAO firstUnseenDAO;
     private final CassandraDeletedMessageDAO deletedMessageDAO;
+    private final CassandraMailboxCounterDAO counterDAO;
 
     @Inject
     public DeleteMessageListener(CassandraMessageIdToImapUidDAO imapUidDAO, CassandraMessageIdDAO messageIdDAO, CassandraMessageDAO messageDAO,
                                  CassandraAttachmentDAOV2 attachmentDAO, CassandraAttachmentOwnerDAO ownerDAO,
                                  CassandraAttachmentMessageIdDAO attachmentMessageIdDAO, CassandraACLMapper aclMapper,
                                  CassandraUserMailboxRightsDAO rightsDAO, CassandraApplicableFlagDAO applicableFlagDAO,
-                                 CassandraFirstUnseenDAO firstUnseenDAO, CassandraDeletedMessageDAO deletedMessageDAO) {
+                                 CassandraFirstUnseenDAO firstUnseenDAO, CassandraDeletedMessageDAO deletedMessageDAO, CassandraMailboxCounterDAO counterDAO) {
         this.imapUidDAO = imapUidDAO;
         this.messageIdDAO = messageIdDAO;
         this.messageDAO = messageDAO;
@@ -89,6 +91,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
         this.applicableFlagDAO = applicableFlagDAO;
         this.firstUnseenDAO = firstUnseenDAO;
         this.deletedMessageDAO = deletedMessageDAO;
+        this.counterDAO = counterDAO;
     }
 
     @Override
@@ -128,6 +131,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
                 .then(applicableFlagDAO.delete(mailboxId))
                 .then(firstUnseenDAO.removeAll(mailboxId))
                 .then(deletedMessageDAO.removeAll(mailboxId))
+                .then(counterDAO.delete(mailboxId))
                 .block();
         }
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java
index e9fb398..80ae4ba 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java
@@ -41,6 +41,7 @@ import com.datastax.driver.core.BoundStatement;
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.querybuilder.Assignment;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
 
 import reactor.core.publisher.Mono;
 
@@ -56,6 +57,7 @@ public class CassandraMailboxCounterDAO {
     private final PreparedStatement decrementMessageCountStatement;
     private final PreparedStatement incrementUnseenAndCountStatement;
     private final PreparedStatement decrementUnseenAndCountStatement;
+    private final PreparedStatement deleteStatement;
 
     @Inject
     public CassandraMailboxCounterDAO(Session session) {
@@ -81,6 +83,8 @@ public class CassandraMailboxCounterDAO {
             .with(decr(COUNT))
             .and(decr(UNSEEN))
             .where(eq(MAILBOX_ID, bindMarker(MAILBOX_ID))));
+        deleteStatement = session.prepare(QueryBuilder.delete().from(TABLE_NAME)
+            .where(eq(MAILBOX_ID, bindMarker(MAILBOX_ID))));
     }
 
     private PreparedStatement createReadStatement(Session session) {
@@ -97,6 +101,10 @@ public class CassandraMailboxCounterDAO {
                 .where(eq(MAILBOX_ID, bindMarker(MAILBOX_ID))));
     }
 
+    public Mono<Void> delete(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, deleteStatement));
+    }
+
     public Mono<MailboxCounters> retrieveMailboxCounters(CassandraId mailboxId) {
         return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(mailboxId, readStatement))
             .map(row ->  MailboxCounters.builder()
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 5f78c72..36ca5d8 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
@@ -47,6 +47,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMailboxCounterDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
@@ -673,6 +674,38 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
                 .isEmpty();
         }
 
+        @Test
+        void deleteMailboxShouldCleanUpMailboxCounters(CassandraCluster cassandraCluster) throws Exception {
+            inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            assertThat(countersDAO(cassandraCluster).retrieveMailboxCounters((CassandraId) inboxId)
+                .blockOptional())
+                .isEmpty();
+        }
+
+        @Test
+        void deleteMailboxShouldCleanUpMailboxCountersWhenFailure(CassandraCluster cassandraCluster) throws Exception {
+            inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM mailboxCounters WHERE mailboxId=:mailboxId;"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            assertThat(countersDAO(cassandraCluster).retrieveMailboxCounters((CassandraId) inboxId)
+                .blockOptional())
+                .isEmpty();
+        }
+
+        private CassandraMailboxCounterDAO countersDAO(CassandraCluster cassandraCluster) {
+            return new CassandraMailboxCounterDAO(cassandraCluster.getConf());
+        }
+
         private CassandraDeletedMessageDAO deletedMessageDAO(CassandraCluster cassandraCluster) {
             return new CassandraDeletedMessageDAO(cassandraCluster.getConf());
         }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAOTest.java
index 558e58a..e00c0e0 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAOTest.java
@@ -20,6 +20,7 @@
 package org.apache.james.mailbox.cassandra.mail;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
@@ -143,6 +144,22 @@ class CassandraMailboxCounterDAOTest {
     }
 
     @Test
+    void retrieveMailboxCounterShouldNotReturnDeletedItems() {
+        testee.incrementCount(MAILBOX_ID).block();
+        testee.incrementUnseen(MAILBOX_ID).block();
+
+        testee.delete(MAILBOX_ID).block();
+
+        assertThat(testee.retrieveMailboxCounters(MAILBOX_ID).blockOptional())
+            .isEmpty();
+    }
+
+    @Test
+    void deleteShouldNotThrowWhenNoData() {
+        assertThatCode(() -> testee.delete(MAILBOX_ID).block()).doesNotThrowAnyException();
+    }
+
+    @Test
     void decrementCountShouldRemoveOne() {
         testee.incrementCount(MAILBOX_ID).block();
 


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


[james-project] 05/22: JAMES-3148 MessageRepresentation should only ship information stored in CassandraMessageDAO

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 a6b44ca3ecf647b50acfd9bd5144cb97bfd71431
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 13:08:39 2020 +0700

    JAMES-3148 MessageRepresentation should only ship information stored in CassandraMessageDAO
    
    Caller should carry over the mailbox context
    
    This allows reading basic metadata without the mailbox content of a message.
---
 .../mailbox/cassandra/mail/AttachmentLoader.java   |  9 ++++--
 .../cassandra/mail/CassandraMessageDAO.java        | 24 +++++++--------
 .../cassandra/mail/CassandraMessageIdMapper.java   |  3 +-
 .../cassandra/mail/CassandraMessageMapper.java     |  7 +++--
 .../cassandra/mail/MessageRepresentation.java      | 34 ++++------------------
 5 files changed, 28 insertions(+), 49 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoader.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoader.java
index a765dcd..17f0975 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoader.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoader.java
@@ -21,7 +21,9 @@ package org.apache.james.mailbox.cassandra.mail;
 import java.util.List;
 import java.util.stream.Stream;
 
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.mailbox.model.AttachmentMetadata;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.MessageAttachmentMetadata;
 import org.apache.james.mailbox.store.mail.MessageMapper;
 import org.apache.james.mailbox.store.mail.model.MailboxMessage;
@@ -41,9 +43,10 @@ public class AttachmentLoader {
         this.attachmentMapper = attachmentMapper;
     }
 
-    public Mono<MailboxMessage> addAttachmentToMessage(MessageRepresentation messageRepresentation, MessageMapper.FetchType fetchType) {
-        return loadAttachments(messageRepresentation.getAttachments().stream(), fetchType)
-            .map(messageRepresentation::toMailboxMessage);
+    public Mono<MailboxMessage> addAttachmentToMessage(Pair<ComposedMessageIdWithMetaData, MessageRepresentation> messageRepresentation,
+                                                       MessageMapper.FetchType fetchType) {
+        return loadAttachments(messageRepresentation.getRight().getAttachments().stream(), fetchType)
+            .map(attachments -> messageRepresentation.getRight().toMailboxMessage(messageRepresentation.getLeft(), attachments));
     }
 
     private Mono<List<MessageAttachmentMetadata>> loadAttachments(Stream<MessageAttachmentRepresentation> messageAttachmentRepresentations, MessageMapper.FetchType fetchType) {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
index 07dfbd1..baa1466 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
@@ -64,7 +64,6 @@ import org.apache.james.mailbox.cassandra.table.CassandraMessageV2Table.Properti
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.Cid;
-import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
 import org.apache.james.mailbox.model.MessageAttachmentMetadata;
 import org.apache.james.mailbox.store.mail.MessageMapper.FetchType;
@@ -227,23 +226,24 @@ public class CassandraMessageDAO {
     }
 
     public Mono<MessageRepresentation> retrieveMessage(ComposedMessageIdWithMetaData id, FetchType fetchType) {
-        return retrieveRow(id, fetchType)
-                .flatMap(resultSet -> message(resultSet, id, fetchType));
+        CassandraMessageId cassandraMessageId = (CassandraMessageId) id.getComposedMessageId().getMessageId();
+        return retrieveMessage(fetchType, cassandraMessageId);
     }
 
-    private Mono<ResultSet> retrieveRow(ComposedMessageIdWithMetaData messageId, FetchType fetchType) {
-        CassandraMessageId cassandraMessageId = (CassandraMessageId) messageId.getComposedMessageId().getMessageId();
+    private Mono<MessageRepresentation> retrieveMessage(FetchType fetchType, CassandraMessageId cassandraMessageId) {
+        return retrieveRow(cassandraMessageId, fetchType)
+                .flatMap(resultSet -> message(resultSet, cassandraMessageId, fetchType));
+    }
 
+    private Mono<ResultSet> retrieveRow(CassandraMessageId messageId, FetchType fetchType) {
         return cassandraAsyncExecutor.execute(retrieveSelect(fetchType)
             .bind()
-            .setUUID(MESSAGE_ID, cassandraMessageId.get())
+            .setUUID(MESSAGE_ID, messageId.get())
             .setConsistencyLevel(QUORUM));
     }
 
     private Mono<MessageRepresentation>
-    message(ResultSet rows,ComposedMessageIdWithMetaData messageIdWithMetaData, FetchType fetchType) {
-        ComposedMessageId messageId = messageIdWithMetaData.getComposedMessageId();
-
+    message(ResultSet rows, CassandraMessageId cassandraMessageId, FetchType fetchType) {
         if (rows.isExhausted()) {
             return Mono.empty();
         }
@@ -251,16 +251,12 @@ public class CassandraMessageDAO {
         Row row = rows.one();
         return buildContentRetriever(fetchType, row).map(content ->
             new MessageRepresentation(
-                messageId.getMessageId(),
+                cassandraMessageId,
                 row.getTimestamp(INTERNAL_DATE),
                 row.getLong(FULL_CONTENT_OCTETS),
                 row.getInt(BODY_START_OCTET),
                 new SharedByteArrayInputStream(content),
-                messageIdWithMetaData.getFlags(),
                 getPropertyBuilder(row),
-                messageId.getMailboxId(),
-                messageId.getUid(),
-                messageIdWithMetaData.getModSeq(),
                 hasAttachment(row),
                 getAttachments(row).collect(Guavate.toImmutableList())));
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
index 43b3c7c..281fb2b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
@@ -101,7 +101,8 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
     public Flux<MailboxMessage> findReactive(Collection<MessageId> messageIds, FetchType fetchType) {
         return Flux.fromStream(messageIds.stream())
             .flatMap(messageId -> imapUidDAO.retrieve((CassandraMessageId) messageId, Optional.empty()), cassandraConfiguration.getMessageReadChunkSize())
-            .flatMap(composedMessageId -> messageDAO.retrieveMessage(composedMessageId, fetchType), cassandraConfiguration.getMessageReadChunkSize())
+            .flatMap(composedMessageId -> messageDAO.retrieveMessage(composedMessageId, fetchType)
+                .map(messageRepresentation -> Pair.of(composedMessageId, messageRepresentation)), cassandraConfiguration.getMessageReadChunkSize())
             .flatMap(messageRepresentation -> attachmentLoader.addAttachmentToMessage(messageRepresentation, fetchType), cassandraConfiguration.getMessageReadChunkSize())
             .groupBy(MailboxMessage::getMailboxId)
             .flatMap(this::keepMessageIfMailboxExists);
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
index f5b9d55..465c9cf 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
@@ -29,6 +29,7 @@ import java.util.Optional;
 import javax.mail.Flags;
 import javax.mail.Flags.Flag;
 
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.mailbox.ApplicableFlagBuilder;
 import org.apache.james.mailbox.FlagsBuilder;
@@ -172,7 +173,7 @@ public class CassandraMessageMapper implements MessageMapper {
 
     private Mono<MailboxMessage> retrieveMessage(ComposedMessageIdWithMetaData messageId, FetchType fetchType) {
         return messageDAO.retrieveMessage(messageId, fetchType)
-            .flatMap(messageRepresentation -> attachmentLoader.addAttachmentToMessage(messageRepresentation, fetchType));
+            .flatMap(messageRepresentation -> attachmentLoader.addAttachmentToMessage(Pair.of(messageId, messageRepresentation), fetchType));
     }
 
     @Override
@@ -213,8 +214,8 @@ public class CassandraMessageMapper implements MessageMapper {
     private Mono<SimpleMailboxMessage> expungeOne(CassandraId mailboxId, MessageUid messageUid) {
         return retrieveComposedId(mailboxId, messageUid)
             .flatMap(idWithMetadata -> deleteUsingMailboxId(idWithMetadata).thenReturn(idWithMetadata))
-            .flatMap(idWithMetadata -> messageDAO.retrieveMessage(idWithMetadata, FetchType.Metadata))
-            .map(pair -> pair.toMailboxMessage(ImmutableList.of()));
+            .flatMap(idWithMetadata -> messageDAO.retrieveMessage(idWithMetadata, FetchType.Metadata)
+                .map(pair -> pair.toMailboxMessage(idWithMetadata, ImmutableList.of())));
     }
 
     private Mono<ComposedMessageIdWithMetaData> retrieveComposedId(CassandraId mailboxId, MessageUid uid) {
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/MessageRepresentation.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/MessageRepresentation.java
index 5416730..d627f2b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/MessageRepresentation.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/MessageRepresentation.java
@@ -22,14 +22,9 @@ package org.apache.james.mailbox.cassandra.mail;
 import java.util.Date;
 import java.util.List;
 
-import javax.mail.Flags;
 import javax.mail.util.SharedByteArrayInputStream;
 
-import org.apache.james.mailbox.MessageUid;
-import org.apache.james.mailbox.ModSeq;
-import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
-import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageAttachmentMetadata;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
@@ -41,60 +36,43 @@ public class MessageRepresentation {
     private final Long size;
     private final Integer bodySize;
     private final SharedByteArrayInputStream content;
-    private final Flags flags;
     private final PropertyBuilder propertyBuilder;
-    private final MailboxId mailboxId;
-    private final MessageUid messageUid;
-    private final ModSeq modSeq;
     private final boolean hasAttachment;
     private final List<MessageAttachmentRepresentation> attachments;
 
     public MessageRepresentation(MessageId messageId, Date internalDate, Long size, Integer bodySize, SharedByteArrayInputStream content,
-                                 Flags flags, PropertyBuilder propertyBuilder, MailboxId mailboxId, MessageUid messageUid, ModSeq modSeq,
-                                 boolean hasAttachment, List<MessageAttachmentRepresentation> attachments) {
+                                 PropertyBuilder propertyBuilder, boolean hasAttachment, List<MessageAttachmentRepresentation> attachments) {
         this.messageId = messageId;
         this.internalDate = internalDate;
         this.size = size;
         this.bodySize = bodySize;
         this.content = content;
-        this.flags = flags;
         this.propertyBuilder = propertyBuilder;
-        this.mailboxId = mailboxId;
-        this.messageUid = messageUid;
-        this.modSeq = modSeq;
         this.hasAttachment = hasAttachment;
         this.attachments = attachments;
     }
 
-    public SimpleMailboxMessage toMailboxMessage(List<MessageAttachmentMetadata> attachments) {
+    public SimpleMailboxMessage toMailboxMessage(ComposedMessageIdWithMetaData metadata, List<MessageAttachmentMetadata> attachments) {
         return SimpleMailboxMessage.builder()
             .messageId(messageId)
-            .mailboxId(mailboxId)
-            .uid(messageUid)
-            .modseq(modSeq)
+            .mailboxId(metadata.getComposedMessageId().getMailboxId())
+            .uid(metadata.getComposedMessageId().getUid())
+            .modseq(metadata.getModSeq())
             .internalDate(internalDate)
             .bodyStartOctet(bodySize)
             .size(size)
             .content(content)
-            .flags(flags)
+            .flags(metadata.getFlags())
             .propertyBuilder(propertyBuilder)
             .addAttachments(attachments)
             .hasAttachment(hasAttachment)
             .build();
     }
 
-    public MailboxId getMailboxId() {
-        return mailboxId;
-    }
-
     public MessageId getMessageId() {
         return messageId;
     }
 
-    public ComposedMessageIdWithMetaData getMetadata() {
-        return new ComposedMessageIdWithMetaData(new ComposedMessageId(mailboxId, messageId, messageUid), flags, modSeq);
-    }
-
     public SharedByteArrayInputStream getContent() {
         return content;
     }


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


[james-project] 22/22: JAMES-3148 DeletionTests should leverage the use of AppendResult

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 59a0b233fe625b4ac7bcc002db51bc959bb9765d
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Apr 23 09:27:26 2020 +0200

    JAMES-3148 DeletionTests should leverage the use of AppendResult
---
 .../cassandra/CassandraMailboxManagerTest.java     | 100 ++++++++++-----------
 .../mail/CassandraAttachmentDAOV2Test.java         |   4 +-
 2 files changed, 52 insertions(+), 52 deletions(-)

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 2a2dc63..6e35beb 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
@@ -38,6 +38,7 @@ import org.apache.james.core.Username;
 import org.apache.james.mailbox.MailboxManagerTest;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.MessageManager.AppendResult;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
@@ -56,12 +57,11 @@ import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.model.AttachmentId;
-import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.FetchGroup;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.MessageAttachment;
+import org.apache.james.mailbox.model.MessageAttachmentMetadata;
 import org.apache.james.mailbox.model.MessageRange;
 import org.apache.james.mailbox.model.MessageResult;
 import org.apache.james.mailbox.store.PreDeletionHooks;
@@ -118,21 +118,21 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteMailboxShouldUnreferenceMessageMetadata(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
             mailboxManager.deleteMailbox(inbox, session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
-                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
+                CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
@@ -153,13 +153,13 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteAttachmentFails(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
@@ -170,8 +170,8 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
-                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
+                CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
@@ -192,13 +192,13 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteMessageFails(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
@@ -209,8 +209,8 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
-                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
+                CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
@@ -231,13 +231,13 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteMailboxContextFails(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
@@ -248,8 +248,8 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
-                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
+                CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
@@ -270,13 +270,13 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteMailboxContextByIdFails(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
@@ -287,8 +287,8 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
-                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
+                CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
@@ -309,20 +309,20 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteShouldUnreferenceMessageMetadata(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
-            inboxManager.delete(ImmutableList.of(composedMessageId.getUid()), session);
+            inboxManager.delete(ImmutableList.of(appendResult.getId().getUid()), session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
@@ -337,13 +337,13 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteShouldUnreferenceMessageMetadataWhenDeleteMessageFails(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
@@ -351,10 +351,10 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
                 .times(1)
                 .whenQueryStartsWith("DELETE FROM messageV2 WHERE messageId=:messageId;"));
 
-            inboxManager.delete(ImmutableList.of(composedMessageId.getUid()), session);
+            inboxManager.delete(ImmutableList.of(appendResult.getId().getUid()), session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
@@ -369,13 +369,13 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteShouldUnreferenceMessageMetadataWhenDeleteAttachmentFails(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
@@ -383,10 +383,10 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
                 .times(1)
                 .whenQueryStartsWith("DELETE FROM attachmentV2 WHERE idAsUUID=:idAsUUID;"));
 
-            inboxManager.delete(ImmutableList.of(composedMessageId.getUid()), session);
+            inboxManager.delete(ImmutableList.of(appendResult.getId().getUid()), session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
@@ -401,13 +401,13 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteMailboxShouldNotUnreferenceMessageMetadataWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
@@ -416,8 +416,8 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
-                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
+                CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isPresent();
@@ -438,22 +438,22 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteShouldNotUnreferenceMessageMetadataWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
             mailboxManager.copyMessages(MessageRange.all(), inboxId, otherBoxManager.getId(), session);
 
-            inboxManager.delete(ImmutableList.of(composedMessageId.getUid()), session);
+            inboxManager.delete(ImmutableList.of(appendResult.getId().getUid()), session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isPresent();
@@ -468,13 +468,13 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteMailboxShouldNotUnreferenceAttachmentWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
@@ -483,8 +483,8 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
-                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
+                CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
@@ -505,22 +505,22 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
 
         @Test
         void deleteShouldNotUnreferenceAttachmentWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
-            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+            AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
 
             AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
                 .map(Throwing.function(MessageResult::getLoadedAttachments))
                 .flatMap(Collection::stream)
-                .map(MessageAttachment::getAttachmentId)
+                .map(MessageAttachmentMetadata::getAttachmentId)
                 .findFirst()
                 .get();
 
             new CassandraAttachmentOwnerDAO(cassandraCluster.getConf()).addOwner(attachmentId, Username.of("bob")).block();
 
-            inboxManager.delete(ImmutableList.of(composedMessageId.getUid()), session);
+            inboxManager.delete(ImmutableList.of(appendResult.getId().getUid()), session);
 
             SoftAssertions.assertSoftly(softly -> {
-                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
 
                 softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
                     .blockOptional()).isEmpty();
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2Test.java
index 94a05ba..00e5e6f 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2Test.java
@@ -81,10 +81,10 @@ class CassandraAttachmentDAOV2Test {
 
     @Test
     void getAttachmentShouldNotReturnDeletedAttachments() {
-        Attachment attachment = Attachment.builder()
+        AttachmentMetadata attachment = AttachmentMetadata.builder()
             .attachmentId(ATTACHMENT_ID)
             .type("application/json")
-            .bytes("{\"property\":`\"value\"}".getBytes(StandardCharsets.UTF_8))
+            .size(36)
             .build();
         BlobId blobId = BLOB_ID_FACTORY.from("blobId");
         DAOAttachment daoAttachment = CassandraAttachmentDAOV2.from(attachment, blobId);


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


[james-project] 13/22: JAMES-3148 ACL cleanUp upon mailbox deletion

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 456e83e544a0dc98780e3af3fcb64b4a120a962b
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 16:53:20 2020 +0700

    JAMES-3148 ACL cleanUp upon mailbox deletion
---
 .../CassandraMailboxSessionMapperFactory.java      |  2 +-
 .../mailbox/cassandra/DeleteMessageListener.java   | 32 +++++++---
 .../cassandra/CassandraMailboxManagerTest.java     | 71 ++++++++++++++++++++++
 3 files changed, 95 insertions(+), 10 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
index 7d29e36..b61508b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
@@ -204,6 +204,6 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa
     }
 
     public DeleteMessageListener deleteMessageListener() {
-        return new DeleteMessageListener(imapUidDAO, messageIdDAO, messageDAO, attachmentDAOV2, ownerDAO, attachmentMessageIdDAO);
+        return new DeleteMessageListener(imapUidDAO, messageIdDAO, messageDAO, attachmentDAOV2, ownerDAO, attachmentMessageIdDAO, aclMapper, userMailboxRightsDAO);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index 81afcd1..1831416 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -25,20 +25,24 @@ import java.util.Optional;
 
 import javax.inject.Inject;
 
+import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 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.MessageAttachmentRepresentation;
 import org.apache.james.mailbox.cassandra.mail.MessageRepresentation;
 import org.apache.james.mailbox.events.Event;
 import org.apache.james.mailbox.events.Group;
 import org.apache.james.mailbox.events.MailboxListener;
 import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
+import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MessageMetaData;
 import org.apache.james.mailbox.model.MessageRange;
 import org.apache.james.mailbox.store.mail.MessageMapper;
@@ -53,25 +57,29 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
 
     }
 
+    private final CassandraMessageIdToImapUidDAO imapUidDAO;
+    private final CassandraMessageIdDAO messageIdDAO;
+    private final CassandraMessageDAO messageDAO;
+    private final CassandraAttachmentDAOV2 attachmentDAO;
+    private final CassandraAttachmentOwnerDAO ownerDAO;
+    private final CassandraAttachmentMessageIdDAO attachmentMessageIdDAO;
+    private final CassandraACLMapper aclMapper;
+    private final CassandraUserMailboxRightsDAO rightsDAO;
+
     @Inject
     public DeleteMessageListener(CassandraMessageIdToImapUidDAO imapUidDAO, CassandraMessageIdDAO messageIdDAO, CassandraMessageDAO messageDAO,
                                  CassandraAttachmentDAOV2 attachmentDAO, CassandraAttachmentOwnerDAO ownerDAO,
-                                 CassandraAttachmentMessageIdDAO attachmentMessageIdDAO) {
+                                 CassandraAttachmentMessageIdDAO attachmentMessageIdDAO, CassandraACLMapper aclMapper, CassandraUserMailboxRightsDAO rightsDAO) {
         this.imapUidDAO = imapUidDAO;
         this.messageIdDAO = messageIdDAO;
         this.messageDAO = messageDAO;
         this.attachmentDAO = attachmentDAO;
         this.ownerDAO = ownerDAO;
         this.attachmentMessageIdDAO = attachmentMessageIdDAO;
+        this.aclMapper = aclMapper;
+        this.rightsDAO = rightsDAO;
     }
 
-    private final CassandraMessageIdToImapUidDAO imapUidDAO;
-    private final CassandraMessageIdDAO messageIdDAO;
-    private final CassandraMessageDAO messageDAO;
-    private final CassandraAttachmentDAOV2 attachmentDAO;
-    private final CassandraAttachmentOwnerDAO ownerDAO;
-    private final CassandraAttachmentMessageIdDAO attachmentMessageIdDAO;
-
     @Override
     public Group getDefaultGroup() {
         return new DeleteMessageListenerGroup();
@@ -105,11 +113,17 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
                 .concatMap(metadata -> handleDeletion((CassandraMessageId) metadata.getMessageId(), mailboxId)
                     .then(imapUidDAO.delete((CassandraMessageId) metadata.getMessageId(), mailboxId))
                     .then(messageIdDAO.delete(mailboxId, metadata.getUid())))
-                .then()
+                .then(deleteAcl(mailboxId))
                 .block();
         }
     }
 
+    private Mono<Void> deleteAcl(CassandraId mailboxId) {
+        return aclMapper.getACL(mailboxId)
+            .flatMap(acl -> rightsDAO.update(mailboxId, ACLDiff.computeDiff(acl, MailboxACL.EMPTY)))
+            .then(aclMapper.delete(mailboxId));
+    }
+
     private Mono<Void> handleDeletion(CassandraMessageId messageId) {
         return Mono.just(messageId)
             .filterWhen(this::isReferenced)
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 8d14e71..b08c9a0 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
@@ -24,8 +24,11 @@ import static org.mockito.Mockito.mock;
 import java.util.Collection;
 import java.util.Optional;
 
+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.utils.CassandraUtils;
 import org.apache.james.blob.api.BlobStore;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.core.Username;
@@ -34,17 +37,20 @@ import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
+import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 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.events.EventBus;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.FetchGroup;
+import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageAttachment;
@@ -65,6 +71,7 @@ import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
 import com.github.fge.lambdas.Throwing;
 
 public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMailboxManager> {
+    public static final Username BOB = Username.of("Bob");
     @RegisterExtension
     static CassandraClusterExtension cassandra = new CassandraClusterExtension(MailboxAggregateModule.MODULE_WITH_QUOTA);
 
@@ -518,6 +525,70 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             });
         }
 
+        @Test
+        void deleteMailboxShouldCleanupACL(CassandraCluster cassandraCluster) throws Exception {
+            mailboxManager.setRights(inboxId, new MailboxACL(
+                Pair.of(MailboxACL.EntryKey.createUserEntryKey(BOB), new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read))), session);
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraId id = (CassandraId) this.inboxId;
+
+                softly.assertThat(aclMapper(cassandraCluster).getACL(id).blockOptional()).isEmpty();
+
+                softly.assertThat(rightsDAO(cassandraCluster).listRightsForUser(BOB).collectList().block()).isEmpty();
+            });
+        }
+
+        @Test
+        void deleteMailboxShouldCleanupACLWhenRightDeleteFails(CassandraCluster cassandraCluster) throws Exception {
+            mailboxManager.setRights(inboxId, new MailboxACL(
+                Pair.of(MailboxACL.EntryKey.createUserEntryKey(BOB), new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read))), session);
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM UserMailboxACL WHERE userName=:userName AND mailboxid=:mailboxid;"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraId id = (CassandraId) this.inboxId;
+
+                softly.assertThat(aclMapper(cassandraCluster).getACL(id).blockOptional()).isEmpty();
+
+                softly.assertThat(rightsDAO(cassandraCluster).listRightsForUser(BOB).collectList().block()).isEmpty();
+            });
+        }
+
+        @Test
+        void deleteMailboxShouldCleanupACLWhenACLDeleteFails(CassandraCluster cassandraCluster) throws Exception {
+            mailboxManager.setRights(inboxId, new MailboxACL(
+                Pair.of(MailboxACL.EntryKey.createUserEntryKey(BOB), new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read))), session);
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM acl WHERE id=:id IF EXISTS;"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraId id = (CassandraId) this.inboxId;
+
+                softly.assertThat(aclMapper(cassandraCluster).getACL(id).blockOptional()).isEmpty();
+
+                softly.assertThat(rightsDAO(cassandraCluster).listRightsForUser(BOB).collectList().block()).isEmpty();
+            });
+        }
+
+        private CassandraACLMapper aclMapper(CassandraCluster cassandraCluster) {
+            return new CassandraACLMapper(cassandraCluster.getConf(), rightsDAO(cassandraCluster), CassandraConfiguration.DEFAULT_CONFIGURATION);
+        }
+
+        private CassandraUserMailboxRightsDAO rightsDAO(CassandraCluster cassandraCluster) {
+            return new CassandraUserMailboxRightsDAO(cassandraCluster.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
+        }
+
         private CassandraAttachmentMessageIdDAO attachmentMessageIdDAO(CassandraCluster cassandraCluster) {
             return new CassandraAttachmentMessageIdDAO(cassandraCluster.getConf(), new CassandraMessageId.Factory());
         }


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


[james-project] 02/22: [Documentation] Fix README docker compilation path

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 c3fa19501af0c08ebace20dd9b46a9bad89b4d74
Author: Rene Cordier <rc...@linagora.com>
AuthorDate: Tue May 5 15:43:39 2020 +0700

    [Documentation] Fix README docker compilation path
    
    The correct folder is java-11 for docker compilation now, not java-8 anymore
---
 README.adoc | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/README.adoc b/README.adoc
index 6b2cbee..7fc1c38 100644
--- a/README.adoc
+++ b/README.adoc
@@ -157,7 +157,7 @@ Don't forget to add your key to https://downloads.apache.org/james/KEYS
 
 == How to check the compilation
 
-In order to have a standard compilation environment, we introduce Dockerfiles, using java-8.
+In order to have a standard compilation environment, we introduce Dockerfiles, using java-11.
 
 === Java 11
 
@@ -211,7 +211,7 @@ This feature is available for three configurations :
 Built artifacts should be in ./dockerfiles/run/guice/cassandra-rabbitmq/destination folder for cassandra.
 If you haven't already:
 
-    $ docker build -t james/project dockerfiles/compilation/java-8
+    $ docker build -t james/project dockerfiles/compilation/java-11
     $ docker run -v $HOME/.m2:/root/.m2 -v $PWD:/origin \
   -v $PWD/dockerfiles/run/guice/cassandra-rabbitmq/destination:/cassandra-rabbitmq/destination \
   -t james/project -s HEAD
@@ -301,7 +301,7 @@ Add a link for the tika container in the above command line:
 Built artifacts should be in ./dockerfiles/run/guice/cassandra/destination folder for cassandra.
 If you haven't already:
 
-    $ docker build -t james/project dockerfiles/compilation/java-8
+    $ docker build -t james/project dockerfiles/compilation/java-11
     $ docker run -v $HOME/.m2:/root/.m2 -v $PWD:/origin \
   -v $PWD/dockerfiles/run/guice/cassandra/destination:/cassandra/destination \
   -t james/project -s HEAD
@@ -362,7 +362,7 @@ Add a link for the tika container in the above command line:
 Built artifacts should be in ./dockerfiles/run/guice/jpa/destination folder for jpa.
 If you haven't already:
 
-    $ docker build -t james/project dockerfiles/compilation/java-8
+    $ docker build -t james/project dockerfiles/compilation/java-11
     $ docker run -v $HOME/.m2:/root/.m2 -v $PWD:/origin \
   -v $PWD/dockerfiles/run/guice/jpa/destination:/jpa/destination \
   -t james/project -s HEAD
@@ -398,7 +398,7 @@ To have log file accessible on a volume, add *-v  $PWD/logs:/logs* option to the
 Built artifacts should be in ./dockerfiles/run/spring/destination folder for Spring.
 If you haven't already:
 
-    $ docker build -t james/project dockerfiles/compilation/java-8
+    $ docker build -t james/project dockerfiles/compilation/java-11
     $ docker run -v $HOME/.m2:/root/.m2 -v $PWD:/origin \
   -v $PWD/dockerfiles/run/spring/destination:/spring/destination \
   -t james/project -s HEAD


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


[james-project] 06/22: JAMES-3148 CassandraMessageDAO::delete

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 15ddca9951b619aef93bf6ac543087d5fe5b16ec
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 13:55:04 2020 +0700

    JAMES-3148 CassandraMessageDAO::delete
---
 .../cassandra/mail/CassandraAttachmentDAOV2.java   | 14 ++++++++++++
 .../mail/CassandraAttachmentDAOV2Test.java         | 25 ++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java
index 8627a73..ff3ddfe 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java
@@ -45,6 +45,7 @@ import org.apache.james.mailbox.model.ContentType;
 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.google.common.base.Preconditions;
 
 import reactor.core.publisher.Mono;
@@ -125,6 +126,7 @@ public class CassandraAttachmentDAOV2 {
     private final BlobId.Factory blobIdFactory;
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
     private final PreparedStatement insertStatement;
+    private final PreparedStatement deleteStatement;
     private final PreparedStatement selectStatement;
 
     @Inject
@@ -134,6 +136,13 @@ public class CassandraAttachmentDAOV2 {
 
         this.selectStatement = prepareSelect(session);
         this.insertStatement = prepareInsert(session);
+        this.deleteStatement = prepareDelete(session);
+    }
+
+    private PreparedStatement prepareDelete(Session session) {
+        return session.prepare(
+            QueryBuilder.delete().from(TABLE_NAME)
+                .where(eq(ID, bindMarker(ID))));
     }
 
     private PreparedStatement prepareInsert(Session session) {
@@ -171,4 +180,9 @@ public class CassandraAttachmentDAOV2 {
                 .setString(BLOB_ID, attachment.getBlobId().asString()));
     }
 
+    public Mono<Void> delete(AttachmentId attachmentId) {
+        return cassandraAsyncExecutor.executeVoid(
+            deleteStatement.bind()
+                .setUUID(ID_AS_UUID, attachmentId.asUUID()));
+    }
 }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2Test.java
index 23032e1..94a05ba 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2Test.java
@@ -20,6 +20,7 @@
 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.Optional;
 
@@ -57,6 +58,12 @@ class CassandraAttachmentDAOV2Test {
     }
 
     @Test
+    void deleteShouldNotThrowWhenDoesNotExist() {
+        assertThatCode(() -> testee.delete(ATTACHMENT_ID).block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
     void getAttachmentShouldReturnAttachmentWhenStored() {
         AttachmentMetadata attachment = AttachmentMetadata.builder()
             .attachmentId(ATTACHMENT_ID)
@@ -71,4 +78,22 @@ class CassandraAttachmentDAOV2Test {
 
         assertThat(actual).contains(daoAttachment);
     }
+
+    @Test
+    void getAttachmentShouldNotReturnDeletedAttachments() {
+        Attachment attachment = Attachment.builder()
+            .attachmentId(ATTACHMENT_ID)
+            .type("application/json")
+            .bytes("{\"property\":`\"value\"}".getBytes(StandardCharsets.UTF_8))
+            .build();
+        BlobId blobId = BLOB_ID_FACTORY.from("blobId");
+        DAOAttachment daoAttachment = CassandraAttachmentDAOV2.from(attachment, blobId);
+        testee.storeAttachment(daoAttachment).block();
+
+        testee.delete(ATTACHMENT_ID).block();
+
+        Optional<DAOAttachment> actual = testee.getAttachment(ATTACHMENT_ID).blockOptional();
+
+        assertThat(actual).isEmpty();
+    }
 }


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


[james-project] 16/22: JAMES-3148 Cleanup Deleted Messages DAO

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 03d0cf4b19c4efe4902e7c4ecf4409f61238de03
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 20:47:22 2020 +0700

    JAMES-3148 Cleanup Deleted Messages DAO
---
 .../CassandraMailboxSessionMapperFactory.java      |  2 +-
 .../mailbox/cassandra/DeleteMessageListener.java   |  6 +++-
 .../cassandra/mail/CassandraDeletedMessageDAO.java | 13 ++++++++
 .../cassandra/CassandraMailboxManagerTest.java     | 35 ++++++++++++++++++++++
 .../mail/CassandraDeletedMessageDAOTest.java       | 20 +++++++++++++
 5 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
index 13a6d95..ba80ed4 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
@@ -205,6 +205,6 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa
 
     public DeleteMessageListener deleteMessageListener() {
         return new DeleteMessageListener(imapUidDAO, messageIdDAO, messageDAO, attachmentDAOV2, ownerDAO,
-            attachmentMessageIdDAO, aclMapper, userMailboxRightsDAO, applicableFlagDAO, firstUnseenDAO);
+            attachmentMessageIdDAO, aclMapper, userMailboxRightsDAO, applicableFlagDAO, firstUnseenDAO, deletedMessageDAO);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index 7c24b4e..c0f74d9 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -33,6 +33,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
@@ -69,13 +70,14 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
     private final CassandraUserMailboxRightsDAO rightsDAO;
     private final CassandraApplicableFlagDAO applicableFlagDAO;
     private final CassandraFirstUnseenDAO firstUnseenDAO;
+    private final CassandraDeletedMessageDAO deletedMessageDAO;
 
     @Inject
     public DeleteMessageListener(CassandraMessageIdToImapUidDAO imapUidDAO, CassandraMessageIdDAO messageIdDAO, CassandraMessageDAO messageDAO,
                                  CassandraAttachmentDAOV2 attachmentDAO, CassandraAttachmentOwnerDAO ownerDAO,
                                  CassandraAttachmentMessageIdDAO attachmentMessageIdDAO, CassandraACLMapper aclMapper,
                                  CassandraUserMailboxRightsDAO rightsDAO, CassandraApplicableFlagDAO applicableFlagDAO,
-                                 CassandraFirstUnseenDAO firstUnseenDAO) {
+                                 CassandraFirstUnseenDAO firstUnseenDAO, CassandraDeletedMessageDAO deletedMessageDAO) {
         this.imapUidDAO = imapUidDAO;
         this.messageIdDAO = messageIdDAO;
         this.messageDAO = messageDAO;
@@ -86,6 +88,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
         this.rightsDAO = rightsDAO;
         this.applicableFlagDAO = applicableFlagDAO;
         this.firstUnseenDAO = firstUnseenDAO;
+        this.deletedMessageDAO = deletedMessageDAO;
     }
 
     @Override
@@ -124,6 +127,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
                 .then(deleteAcl(mailboxId))
                 .then(applicableFlagDAO.delete(mailboxId))
                 .then(firstUnseenDAO.removeAll(mailboxId))
+                .then(deletedMessageDAO.removeAll(mailboxId))
                 .block();
         }
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java
index cfdebae..8e45984 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java
@@ -53,6 +53,7 @@ public class CassandraDeletedMessageDAO {
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
     private final PreparedStatement addStatement;
     private final PreparedStatement deleteStatement;
+    private final PreparedStatement deleteAllStatement;
 
     private final PreparedStatement selectAllUidStatement;
     private final PreparedStatement selectOneUidStatement;
@@ -65,6 +66,7 @@ public class CassandraDeletedMessageDAO {
         this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
         this.addStatement = prepareAddStatement(session);
         this.deleteStatement = prepareDeleteStatement(session);
+        this.deleteAllStatement = prepareDeleteAllStatement(session);
         this.selectAllUidStatement = prepareAllUidStatement(session);
         this.selectOneUidStatement = prepareOneUidStatement(session);
         this.selectBetweenUidStatement = prepareBetweenUidStatement(session);
@@ -112,6 +114,12 @@ public class CassandraDeletedMessageDAO {
             .and(eq(UID, bindMarker(UID))));
     }
 
+    private PreparedStatement prepareDeleteAllStatement(Session session) {
+        return session.prepare(delete()
+            .from(TABLE_NAME)
+            .where(eq(MAILBOX_ID, bindMarker(MAILBOX_ID))));
+    }
+
     private PreparedStatement prepareAddStatement(Session session) {
         return session.prepare(insertInto(TABLE_NAME)
             .value(MAILBOX_ID, bindMarker(MAILBOX_ID))
@@ -131,6 +139,11 @@ public class CassandraDeletedMessageDAO {
             .setLong(UID, uid.asLong()));
     }
 
+    public Mono<Void> removeAll(CassandraId cassandraId) {
+        return cassandraAsyncExecutor.executeVoid(deleteAllStatement.bind()
+            .setUUID(MAILBOX_ID, cassandraId.asUuid()));
+    }
+
     public Flux<MessageUid> retrieveDeletedMessage(CassandraId cassandraId, MessageRange range) {
         return retrieveResultSetOfDeletedMessage(cassandraId, range)
             .flatMapMany(this::resultSetToFlux);
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 56d9221..5f78c72 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
@@ -45,6 +45,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
@@ -642,6 +643,40 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
                 .isEmpty();
         }
 
+        @Test
+        void deleteMailboxShouldCleanUpDeletedMessages(CassandraCluster cassandraCluster) throws Exception {
+            inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .withFlags(new Flags(Flags.Flag.DELETED))
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            assertThat(deletedMessageDAO(cassandraCluster).retrieveDeletedMessage((CassandraId) inboxId, MessageRange.all())
+                .collectList().block())
+                .isEmpty();
+        }
+
+        @Test
+        void deleteMailboxShouldCleanUpDeletedMessagesWhenFailure(CassandraCluster cassandraCluster) throws Exception {
+            inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .withFlags(new Flags(Flags.Flag.DELETED))
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM messageDeleted WHERE mailboxId=:mailboxId;"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            assertThat(deletedMessageDAO(cassandraCluster).retrieveDeletedMessage((CassandraId) inboxId, MessageRange.all())
+                .collectList().block())
+                .isEmpty();
+        }
+
+        private CassandraDeletedMessageDAO deletedMessageDAO(CassandraCluster cassandraCluster) {
+            return new CassandraDeletedMessageDAO(cassandraCluster.getConf());
+        }
+
         private CassandraFirstUnseenDAO firstUnseenDAO(CassandraCluster cassandraCluster) {
             return new CassandraFirstUnseenDAO(cassandraCluster.getConf());
         }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAOTest.java
index 6197506..f3154fe 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAOTest.java
@@ -20,6 +20,7 @@
 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.List;
 import java.util.UUID;
@@ -76,6 +77,25 @@ class CassandraDeletedMessageDAOTest {
     }
 
     @Test
+    void retrieveDeletedMessageShouldNotReturnDeletedEntries() {
+        testee.addDeleted(MAILBOX_ID, UID_1).block();
+        testee.addDeleted(MAILBOX_ID, UID_2).block();
+
+        testee.removeAll(MAILBOX_ID).block();
+
+        List<MessageUid> result = testee.retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
+                .collectList()
+                .block();
+
+        assertThat(result).isEmpty();
+    }
+
+    @Test
+    void removeAllShouldNotThrowWhenEmpty() {
+        assertThatCode(() -> testee.removeAll(MAILBOX_ID).block()).doesNotThrowAnyException();
+    }
+
+    @Test
     void addDeletedMessageShouldBeIdempotent() {
         testee.addDeleted(MAILBOX_ID, UID_1).block();
         testee.addDeleted(MAILBOX_ID, UID_1).block();


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


[james-project] 20/22: JAMES-3148 DeleteMessageListener: Add class javaDoc

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 f4ceba76c686489202431dc7d85a02b20dc0869b
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 17 14:39:50 2020 +0700

    JAMES-3148 DeleteMessageListener: Add class javaDoc
---
 .../apache/james/mailbox/cassandra/DeleteMessageListener.java | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index 521a59a..ce1a3ce 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -55,6 +55,17 @@ import org.apache.james.mailbox.store.mail.MessageMapper;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
+/**
+ * This listener cleans Cassandra metadata up. It retrieves dandling unreferenced metadata after the delete operation
+ * had been conducted out. Then it deletes the lower levels first so that upon failures undeleted metadata can still be
+ * reached.
+ *
+ * This cleanup is not needed for strict correctness from a MailboxManager point of view thus it could be carried out
+ * asynchronously, via mailbox listeners so that it can be retried.
+ *
+ * Mailbox listener failures lead to eventBus retrying their execution, it ensures the result of the deletion to be
+ * idempotent.
+ */
 public class DeleteMessageListener implements MailboxListener.GroupMailboxListener {
     private static final Optional<CassandraId> ALL_MAILBOXES = Optional.empty();
 


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


[james-project] 10/22: JAMES-3148 Test and correct metadata cleanup upon failures

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 0192d7022f3775039cb6d47d9cd021bfc70f39fe
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 16:29:02 2020 +0700

    JAMES-3148 Test and correct metadata cleanup upon failures
    
    Delete the lowest levels of metadata first so that retries eventually
    clean up everything.
---
 .../mailbox/cassandra/DeleteMessageListener.java   |  22 ++-
 .../cassandra/CassandraMailboxManagerTest.java     | 220 +++++++++++++++++++++
 2 files changed, 239 insertions(+), 3 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index 31529e6..81afcd1 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -102,9 +102,9 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
 
             messageIdDAO.retrieveMessages(mailboxId, MessageRange.all())
                 .map(ComposedMessageIdWithMetaData::getComposedMessageId)
-                .concatMap(metadata -> imapUidDAO.delete((CassandraMessageId) metadata.getMessageId(), mailboxId)
-                    .then(messageIdDAO.delete(mailboxId, metadata.getUid()))
-                    .then(handleDeletion((CassandraMessageId) metadata.getMessageId())))
+                .concatMap(metadata -> handleDeletion((CassandraMessageId) metadata.getMessageId(), mailboxId)
+                    .then(imapUidDAO.delete((CassandraMessageId) metadata.getMessageId(), mailboxId))
+                    .then(messageIdDAO.delete(mailboxId, metadata.getUid())))
                 .then()
                 .block();
         }
@@ -119,6 +119,15 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
                 .then(messageDAO.delete(messageId)));
     }
 
+    private Mono<Void> handleDeletion(CassandraMessageId messageId, CassandraId excludedId) {
+        return Mono.just(messageId)
+            .filterWhen(id -> isReferenced(id, excludedId))
+            .flatMap(id -> readMessage(id)
+                .flatMap(message -> deleteUnreferencedAttachments(message).thenReturn(message))
+                .flatMap(this::deleteAttachmentMessageIds)
+                .then(messageDAO.delete(messageId)));
+    }
+
     private Mono<MessageRepresentation> readMessage(CassandraMessageId id) {
         return messageDAO.retrieveMessage(id, MessageMapper.FetchType.Metadata);
     }
@@ -149,4 +158,11 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
             .hasElements()
             .map(negate());
     }
+
+    private Mono<Boolean> isReferenced(CassandraMessageId id, CassandraId excludedId) {
+        return imapUidDAO.retrieve(id, ALL_MAILBOXES)
+            .filter(metadata -> !metadata.getComposedMessageId().getMailboxId().equals(excludedId))
+            .hasElements()
+            .map(negate());
+    }
 }
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 3f427a3..8d14e71 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
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.james.mailbox.cassandra;
 
+import static org.apache.james.backends.cassandra.Scenario.Builder.fail;
 import static org.mockito.Mockito.mock;
 
 import java.util.Collection;
@@ -135,6 +136,161 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             });
         }
 
+        @Test
+        void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteAttachmentFails(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM attachmentV2 WHERE idAsUUID=:idAsUUID;"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isEmpty();
+
+                softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isEmpty();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .doesNotContain(cassandraMessageId);
+            });
+        }
+
+        @Test
+        void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteMessageFails(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM messageV2 WHERE messageId=:messageId;"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isEmpty();
+
+                softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isEmpty();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .doesNotContain(cassandraMessageId);
+            });
+        }
+
+        @Test
+        void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteMailboxContextFails(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM messageIdTable"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isEmpty();
+
+                softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isEmpty();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .doesNotContain(cassandraMessageId);
+            });
+        }
+
+        @Test
+        void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteMailboxContextByIdFails(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM imapUidTable"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isEmpty();
+
+                softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isEmpty();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .doesNotContain(cassandraMessageId);
+            });
+        }
 
         @Test
         void deleteShouldUnreferenceMessageMetadata(CassandraCluster cassandraCluster) throws Exception {
@@ -165,6 +321,70 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
         }
 
         @Test
+        void deleteShouldUnreferenceMessageMetadataWhenDeleteMessageFails(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM messageV2 WHERE messageId=:messageId;"));
+
+            inboxManager.delete(ImmutableList.of(composedMessageId.getUid()), session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isEmpty();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .doesNotContain(cassandraMessageId);
+            });
+        }
+
+        @Test
+        void deleteShouldUnreferenceMessageMetadataWhenDeleteAttachmentFails(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM attachmentV2 WHERE idAsUUID=:idAsUUID;"));
+
+            inboxManager.delete(ImmutableList.of(composedMessageId.getUid()), session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isEmpty();
+
+                softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
+                    .doesNotContain(cassandraMessageId);
+            });
+        }
+
+        @Test
         void deleteMailboxShouldNotUnreferenceMessageMetadataWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
             ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
                 .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);


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


[james-project] 08/22: JAMES-3148 Add a listener for cleaning mailbox/cassandra upon deletions

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 a42e36ecd7fd6ea24f06735065ce7adb2090ee29
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 14:36:30 2020 +0700

    JAMES-3148 Add a listener for cleaning mailbox/cassandra upon deletions
---
 .../apache/james/mailbox/MailboxManagerTest.java   |   4 +-
 .../CassandraMailboxSessionMapperFactory.java      |   4 +
 .../mailbox/cassandra/DeleteMessageListener.java   | 145 ++++++++++++
 .../cassandra/mail/CassandraMessageDAO.java        |   4 +-
 .../cassandra/CassandraMailboxManagerProvider.java |   1 +
 .../cassandra/CassandraMailboxManagerTest.java     | 255 +++++++++++++++++++++
 .../cassandra/CassandraTestSystemFixture.java      |   1 +
 .../modules/mailbox/CassandraMailboxModule.java    |   7 +-
 8 files changed, 414 insertions(+), 7 deletions(-)

diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index f3dfaa4..28f5f94 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -111,9 +111,9 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
     public static final Username USER_2 = Username.of("USER_2");
     private static final int DEFAULT_MAXIMUM_LIMIT = 256;
 
-    private T mailboxManager;
+    protected T mailboxManager;
     private MailboxSession session;
-    private Message.Builder message;
+    protected Message.Builder message;
 
     private PreDeletionHook preDeletionHook1;
     private PreDeletionHook preDeletionHook2;
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
index c4177b6..7d29e36 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
@@ -202,4 +202,8 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa
         }
         return mapper;
     }
+
+    public DeleteMessageListener deleteMessageListener() {
+        return new DeleteMessageListener(imapUidDAO, messageIdDAO, messageDAO, attachmentDAOV2, ownerDAO, attachmentMessageIdDAO);
+    }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
new file mode 100644
index 0000000..15d7b35
--- /dev/null
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -0,0 +1,145 @@
+/****************************************************************
+ * 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;
+
+import static org.apache.james.util.FunctionalUtils.negate;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
+import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
+import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
+import org.apache.james.mailbox.cassandra.mail.MessageAttachmentRepresentation;
+import org.apache.james.mailbox.cassandra.mail.MessageRepresentation;
+import org.apache.james.mailbox.events.Event;
+import org.apache.james.mailbox.events.Group;
+import org.apache.james.mailbox.events.MailboxListener;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
+import org.apache.james.mailbox.model.MessageMetaData;
+import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.store.mail.MessageMapper;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class DeleteMessageListener implements MailboxListener.GroupMailboxListener {
+    private static final Optional<CassandraId> ALL_MAILBOXES = Optional.empty();
+
+    public static class DeleteMessageListenerGroup extends Group {
+
+    }
+
+    @Inject
+    public DeleteMessageListener(CassandraMessageIdToImapUidDAO imapUidDAO, CassandraMessageIdDAO messageIdDAO, CassandraMessageDAO messageDAO,
+                                 CassandraAttachmentDAOV2 attachmentDAO, CassandraAttachmentOwnerDAO ownerDAO,
+                                 CassandraAttachmentMessageIdDAO attachmentMessageIdDAO) {
+        this.imapUidDAO = imapUidDAO;
+        this.messageIdDAO = messageIdDAO;
+        this.messageDAO = messageDAO;
+        this.attachmentDAO = attachmentDAO;
+        this.ownerDAO = ownerDAO;
+        this.attachmentMessageIdDAO = attachmentMessageIdDAO;
+    }
+
+    private final CassandraMessageIdToImapUidDAO imapUidDAO;
+    private final CassandraMessageIdDAO messageIdDAO;
+    private final CassandraMessageDAO messageDAO;
+    private final CassandraAttachmentDAOV2 attachmentDAO;
+    private final CassandraAttachmentOwnerDAO ownerDAO;
+    private final CassandraAttachmentMessageIdDAO attachmentMessageIdDAO;
+
+    @Override
+    public Group getDefaultGroup() {
+        return new DeleteMessageListenerGroup();
+    }
+
+    @Override
+    public boolean isHandling(Event event) {
+        return event instanceof Expunged || event instanceof MailboxDeletion;
+    }
+
+    @Override
+    public void event(Event event) {
+        if (event instanceof Expunged) {
+            Expunged expunged = (Expunged) event;
+
+            Flux.fromIterable(expunged.getExpunged()
+                .values())
+                .map(MessageMetaData::getMessageId)
+                .map(CassandraMessageId.class::cast)
+                .concatMap(this::handleDeletion)
+                .then()
+                .block();
+        }
+        if (event instanceof MailboxDeletion) {
+            MailboxDeletion mailboxDeletion = (MailboxDeletion) event;
+
+            CassandraId mailboxId = (CassandraId) mailboxDeletion.getMailboxId();
+
+            messageIdDAO.retrieveMessages(mailboxId, MessageRange.all())
+                .map(ComposedMessageIdWithMetaData::getComposedMessageId)
+                .concatMap(metadata -> imapUidDAO.delete((CassandraMessageId) metadata.getMessageId(), mailboxId)
+                    .then(messageIdDAO.delete(mailboxId, metadata.getUid()))
+                    .then(handleDeletion((CassandraMessageId) metadata.getMessageId())))
+                .then()
+                .block();
+        }
+    }
+
+    private Mono<Void> handleDeletion(CassandraMessageId messageId) {
+        return Mono.just(messageId)
+            .filterWhen(this::isReferenced)
+            .flatMap(id -> readMessage(id)
+                .flatMap(this::deleteUnreferencedAttachments)
+                .then(messageDAO.delete(messageId)));
+    }
+
+    private Mono<MessageRepresentation> readMessage(CassandraMessageId id) {
+        return messageDAO.retrieveMessage(id, MessageMapper.FetchType.Metadata);
+    }
+
+    private Mono<Void> deleteUnreferencedAttachments(MessageRepresentation message) {
+        return Flux.fromIterable(message.getAttachments())
+            .filterWhen(attachment -> ownerDAO.retrieveOwners(attachment.getAttachmentId()).hasElements().map(negate()))
+            .filterWhen(attachment -> hasOtherMessagesReferences(message, attachment))
+            .concatMap(attachment -> attachmentDAO.delete(attachment.getAttachmentId()))
+            .then();
+    }
+
+    private Mono<Boolean> hasOtherMessagesReferences(MessageRepresentation message, MessageAttachmentRepresentation attachment) {
+        return attachmentMessageIdDAO.getOwnerMessageIds(attachment.getAttachmentId())
+            .filter(messageId -> !message.getMessageId().equals(messageId))
+            .hasElements()
+            .map(negate());
+    }
+
+    private Mono<Boolean> isReferenced(CassandraMessageId id) {
+        return imapUidDAO.retrieve(id, ALL_MAILBOXES)
+            .hasElements()
+            .map(negate());
+    }
+}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
index baa1466..800b296 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
@@ -227,10 +227,10 @@ public class CassandraMessageDAO {
 
     public Mono<MessageRepresentation> retrieveMessage(ComposedMessageIdWithMetaData id, FetchType fetchType) {
         CassandraMessageId cassandraMessageId = (CassandraMessageId) id.getComposedMessageId().getMessageId();
-        return retrieveMessage(fetchType, cassandraMessageId);
+        return retrieveMessage(cassandraMessageId, fetchType);
     }
 
-    private Mono<MessageRepresentation> retrieveMessage(FetchType fetchType, CassandraMessageId cassandraMessageId) {
+    public Mono<MessageRepresentation> retrieveMessage(CassandraMessageId cassandraMessageId, FetchType fetchType) {
         return retrieveRow(cassandraMessageId, fetchType)
                 .flatMap(resultSet -> message(resultSet, cassandraMessageId, fetchType));
     }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
index ab3dc5d..42ea282 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
@@ -107,6 +107,7 @@ public class CassandraMailboxManagerProvider {
 
         eventBus.register(quotaUpdater);
         eventBus.register(new MailboxAnnotationListener(mapperFactory, sessionProvider));
+        eventBus.register(mapperFactory.deleteMessageListener());
 
         return manager;
     }
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 5cd44e3..55eeb7c 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
@@ -18,13 +18,49 @@
  ****************************************************************/
 package org.apache.james.mailbox.cassandra;
 
+import static org.mockito.Mockito.mock;
+
+import java.util.Collection;
+import java.util.Optional;
+
+import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.blob.api.BlobStore;
+import org.apache.james.blob.api.HashBlobId;
+import org.apache.james.core.Username;
 import org.apache.james.mailbox.MailboxManagerTest;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
+import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
+import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
+import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
 import org.apache.james.mailbox.events.EventBus;
+import org.apache.james.mailbox.model.AttachmentId;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.FetchGroup;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageAttachment;
+import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.model.MessageResult;
 import org.apache.james.mailbox.store.PreDeletionHooks;
+import org.apache.james.mailbox.store.mail.MessageMapper;
 import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.util.ClassLoaderUtils;
+import org.apache.james.util.streams.Iterators;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
+
+import com.github.fge.lambdas.Throwing;
 
 public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMailboxManager> {
     @RegisterExtension
@@ -41,4 +77,223 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
     protected EventBus retrieveEventBus(CassandraMailboxManager mailboxManager) {
         return mailboxManager.getEventBus();
     }
+
+    @Nested
+    class DeletionTests {
+        private MailboxSession session;
+        private MailboxPath inbox;
+        private MailboxId inboxId;
+        private MessageManager inboxManager;
+        private MessageManager otherBoxManager;
+        private MailboxPath newPath;
+
+        @BeforeEach
+        void setUp() throws Exception {
+            session = mailboxManager.createSystemSession(USER_1);
+            inbox = MailboxPath.inbox(session);
+            newPath = MailboxPath.forUser(USER_1, "specialMailbox");
+
+            inboxId = mailboxManager.createMailbox(inbox, session).get();
+            inboxManager = mailboxManager.getMailbox(inbox, session);
+            MailboxId otherId = mailboxManager.createMailbox(newPath, session).get();
+            otherBoxManager = mailboxManager.getMailbox(otherId, session);
+        }
+
+        @Test
+        void deleteMailboxShouldUnreferenceMessageMetadata(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isEmpty();
+
+                softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isEmpty();
+            });
+        }
+
+        @Test
+        void deleteShouldUnreferenceMessageMetadata(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            inboxManager.delete(ImmutableList.of(composedMessageId.getUid()), session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isEmpty();
+            });
+        }
+
+        @Test
+        void deleteMailboxShouldNotUnreferenceMessageMetadataWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            mailboxManager.copyMessages(MessageRange.all(), inboxId, otherBoxManager.getId(), session);
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isPresent();
+
+                softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isPresent();
+            });
+        }
+
+        @Test
+        void deleteShouldNotUnreferenceMessageMetadataWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            mailboxManager.copyMessages(MessageRange.all(), inboxId, otherBoxManager.getId(), session);
+
+            inboxManager.delete(ImmutableList.of(composedMessageId.getUid()), session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isPresent();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isPresent();
+            });
+        }
+
+        @Test
+        void deleteMailboxShouldNotUnreferenceAttachmentWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            new CassandraAttachmentOwnerDAO(cassandraCluster.getConf()).addOwner(attachmentId, Username.of("bob")).block();
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isEmpty();
+
+                softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
+                    .isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isPresent();
+            });
+        }
+
+        @Test
+        void deleteShouldNotUnreferenceAttachmentWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
+            ComposedMessageId composedMessageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
+                .map(Throwing.function(MessageResult::getLoadedAttachments))
+                .flatMap(Collection::stream)
+                .map(MessageAttachment::getAttachmentId)
+                .findFirst()
+                .get();
+
+            new CassandraAttachmentOwnerDAO(cassandraCluster.getConf()).addOwner(attachmentId, Username.of("bob")).block();
+
+            inboxManager.delete(ImmutableList.of(composedMessageId.getUid()), session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                CassandraMessageId cassandraMessageId = (CassandraMessageId) composedMessageId.getMessageId();
+                CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
+
+                softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
+                    .blockOptional()).isEmpty();
+
+                softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
+                    .isPresent();
+            });
+        }
+
+        private CassandraAttachmentDAOV2 attachmentDAO(CassandraCluster cassandraCluster) {
+            return new CassandraAttachmentDAOV2(new HashBlobId.Factory(), cassandraCluster.getConf());
+        }
+
+        private CassandraMessageIdDAO messageIdDAO(CassandraCluster cassandraCluster) {
+            return new CassandraMessageIdDAO(cassandraCluster.getConf(), new CassandraMessageId.Factory());
+        }
+
+        private CassandraMessageIdToImapUidDAO imapUidDAO(CassandraCluster cassandraCluster) {
+            return new CassandraMessageIdToImapUidDAO(cassandraCluster.getConf(), new CassandraMessageId.Factory());
+        }
+
+        private CassandraMessageDAO messageDAO(CassandraCluster cassandraCluster) {
+            return new CassandraMessageDAO(cassandraCluster.getConf(), cassandraCluster.getTypesProvider(),
+                mock(BlobStore.class), new HashBlobId.Factory(), new CassandraMessageId.Factory());
+        }
+    }
 }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
index 6524206..dea017b 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
@@ -80,6 +80,7 @@ public class CassandraTestSystemFixture {
             eventBus, annotationManager, storeRightManager, quotaComponents, index, MailboxManagerConfiguration.DEFAULT, PreDeletionHooks.NO_PRE_DELETION_HOOK);
 
         eventBus.register(new MailboxAnnotationListener(mapperFactory, sessionProvider));
+        eventBus.register(mapperFactory.deleteMessageListener());
 
         return cassandraMailboxManager;
     }
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 7630f5e..a3a0742 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
@@ -38,6 +38,7 @@ import org.apache.james.mailbox.SessionProvider;
 import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.cassandra.CassandraMailboxManager;
 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.CassandraACLMapper;
@@ -192,9 +193,9 @@ public class CassandraMailboxModule extends AbstractModule {
 
         Multibinder.newSetBinder(binder(), MailboxManagerDefinition.class).addBinding().to(CassandraMailboxManagerDefinition.class);
 
-        Multibinder.newSetBinder(binder(), MailboxListener.GroupMailboxListener.class)
-            .addBinding()
-            .to(MailboxAnnotationListener.class);
+        Multibinder<MailboxListener.GroupMailboxListener> mailboxListeners = Multibinder.newSetBinder(binder(), MailboxListener.GroupMailboxListener.class);
+        mailboxListeners.addBinding().to(MailboxAnnotationListener.class);
+        mailboxListeners.addBinding().to(DeleteMessageListener.class);
 
         bind(MailboxManager.class).annotatedWith(Names.named(MAILBOXMANAGER_NAME)).to(MailboxManager.class);
     }


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


[james-project] 14/22: JAMES-3148 Cleanup ApplicableFlags

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 d1dc8ad37763b6fcaace1f28ca3d9eca7d473c58
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Apr 12 20:24:56 2020 +0700

    JAMES-3148 Cleanup ApplicableFlags
---
 .../CassandraMailboxSessionMapperFactory.java      |  3 +-
 .../mailbox/cassandra/DeleteMessageListener.java   |  6 +++-
 .../cassandra/mail/CassandraApplicableFlagDAO.java | 15 +++++++++
 .../cassandra/CassandraMailboxManagerTest.java     | 36 ++++++++++++++++++++++
 .../mail/CassandraApplicableFlagDAOTest.java       | 16 ++++++++++
 5 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
index b61508b..62ccb3a 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
@@ -204,6 +204,7 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa
     }
 
     public DeleteMessageListener deleteMessageListener() {
-        return new DeleteMessageListener(imapUidDAO, messageIdDAO, messageDAO, attachmentDAOV2, ownerDAO, attachmentMessageIdDAO, aclMapper, userMailboxRightsDAO);
+        return new DeleteMessageListener(imapUidDAO, messageIdDAO, messageDAO, attachmentDAOV2, ownerDAO,
+            attachmentMessageIdDAO, aclMapper, userMailboxRightsDAO, applicableFlagDAO);
     }
 }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index 1831416..c4de8cc 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -29,6 +29,7 @@ import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
+import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
@@ -65,11 +66,12 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
     private final CassandraAttachmentMessageIdDAO attachmentMessageIdDAO;
     private final CassandraACLMapper aclMapper;
     private final CassandraUserMailboxRightsDAO rightsDAO;
+    private final CassandraApplicableFlagDAO applicableFlagDAO;
 
     @Inject
     public DeleteMessageListener(CassandraMessageIdToImapUidDAO imapUidDAO, CassandraMessageIdDAO messageIdDAO, CassandraMessageDAO messageDAO,
                                  CassandraAttachmentDAOV2 attachmentDAO, CassandraAttachmentOwnerDAO ownerDAO,
-                                 CassandraAttachmentMessageIdDAO attachmentMessageIdDAO, CassandraACLMapper aclMapper, CassandraUserMailboxRightsDAO rightsDAO) {
+                                 CassandraAttachmentMessageIdDAO attachmentMessageIdDAO, CassandraACLMapper aclMapper, CassandraUserMailboxRightsDAO rightsDAO, CassandraApplicableFlagDAO applicableFlagDAO) {
         this.imapUidDAO = imapUidDAO;
         this.messageIdDAO = messageIdDAO;
         this.messageDAO = messageDAO;
@@ -78,6 +80,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
         this.attachmentMessageIdDAO = attachmentMessageIdDAO;
         this.aclMapper = aclMapper;
         this.rightsDAO = rightsDAO;
+        this.applicableFlagDAO = applicableFlagDAO;
     }
 
     @Override
@@ -114,6 +117,7 @@ public class DeleteMessageListener implements MailboxListener.GroupMailboxListen
                     .then(imapUidDAO.delete((CassandraMessageId) metadata.getMessageId(), mailboxId))
                     .then(messageIdDAO.delete(mailboxId, metadata.getUid())))
                 .then(deleteAcl(mailboxId))
+                .then(applicableFlagDAO.delete(mailboxId))
                 .block();
         }
     }
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java
index cd7398d..2fdb846 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java
@@ -39,6 +39,7 @@ import org.apache.james.mailbox.cassandra.ids.CassandraId;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
 import com.datastax.driver.core.querybuilder.Update;
 import com.datastax.driver.core.querybuilder.Update.Assignments;
 
@@ -48,11 +49,13 @@ public class CassandraApplicableFlagDAO {
 
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
     private final PreparedStatement select;
+    private final PreparedStatement delete;
 
     @Inject
     public CassandraApplicableFlagDAO(Session session) {
         this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
         this.select = prepareSelect(session);
+        this.delete = prepareDelete(session);
     }
 
     private PreparedStatement prepareSelect(Session session) {
@@ -61,6 +64,18 @@ public class CassandraApplicableFlagDAO {
             .where(eq(MAILBOX_ID, bindMarker(MAILBOX_ID))));
     }
 
+    private PreparedStatement prepareDelete(Session session) {
+        return session.prepare(QueryBuilder.delete()
+            .from(TABLE_NAME)
+            .where(eq(MAILBOX_ID, bindMarker(MAILBOX_ID))));
+    }
+
+    public Mono<Void> delete(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeVoid(
+            delete.bind()
+                .setUUID(MAILBOX_ID, mailboxId.asUuid()));
+    }
+
     public Mono<Flags> retrieveApplicableFlag(CassandraId mailboxId) {
         return cassandraAsyncExecutor.executeSingleRow(
             select.bind()
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 b08c9a0..de77b65 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
@@ -19,11 +19,14 @@
 package org.apache.james.mailbox.cassandra;
 
 import static org.apache.james.backends.cassandra.Scenario.Builder.fail;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 
 import java.util.Collection;
 import java.util.Optional;
 
+import javax.mail.Flags;
+
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
@@ -38,6 +41,7 @@ import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
+import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
@@ -581,6 +585,38 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             });
         }
 
+        @Test
+        void deleteMailboxShouldCleanUpApplicableFlags(CassandraCluster cassandraCluster) throws Exception {
+            inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .withFlags(new Flags("custom"))
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            assertThat(applicableFlagDAO(cassandraCluster).retrieveApplicableFlag((CassandraId) inboxId).blockOptional())
+                .isEmpty();
+        }
+
+        @Test
+        void deleteMailboxShouldCleanUpApplicableFlagsAfterAFailure(CassandraCluster cassandraCluster) throws Exception {
+            inboxManager.appendMessage(MessageManager.AppendCommand.builder()
+                .withFlags(new Flags("custom"))
+                .build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
+
+            cassandraCluster.getConf().registerScenario(fail()
+                .times(1)
+                .whenQueryStartsWith("DELETE FROM applicableFlag WHERE mailboxId=:mailboxId;"));
+
+            mailboxManager.deleteMailbox(inbox, session);
+
+            assertThat(applicableFlagDAO(cassandraCluster).retrieveApplicableFlag((CassandraId) inboxId).blockOptional())
+                .isEmpty();
+        }
+
+        private CassandraApplicableFlagDAO applicableFlagDAO(CassandraCluster cassandraCluster) {
+            return new CassandraApplicableFlagDAO(cassandraCluster.getConf());
+        }
+
         private CassandraACLMapper aclMapper(CassandraCluster cassandraCluster) {
             return new CassandraACLMapper(cassandraCluster.getConf(), rightsDAO(cassandraCluster), CassandraConfiguration.DEFAULT_CONFIGURATION);
         }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAOTest.java
index 55f7b5c..710f400 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAOTest.java
@@ -20,6 +20,7 @@
 package org.apache.james.mailbox.cassandra.mail;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
 
 import javax.mail.Flags;
 
@@ -73,6 +74,21 @@ class CassandraApplicableFlagDAOTest {
     }
 
     @Test
+    void retrieveApplicableFlagShouldReturnEmptyWhenDeleted() {
+        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).block();
+
+        testee.delete(CASSANDRA_ID).block();
+
+        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).blockOptional())
+            .isEmpty();
+    }
+    @Test
+    void deleteShouldNotThrowWhenEmpty() {
+        assertThatCode(() -> testee.delete(CASSANDRA_ID).block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
     void updateApplicableFlagsShouldUnionUserFlags() {
         testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).block();
         testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG2)).block();


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


[james-project] 19/22: JAMES-3148 Readability enhencements: method extractions and renames

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 ecbbc2f7ba69e8e086d6eb4e70b2e0b460eddead
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Apr 14 12:16:04 2020 +0700

    JAMES-3148 Readability enhencements: method extractions and renames
---
 .../cassandra/CassandraMailboxManagerTest.java     | 18 +++++++-----
 .../mail/CassandraApplicableFlagDAOTest.java       |  2 +-
 .../mail/CassandraDeletedMessageDAOTest.java       |  4 +--
 .../mail/CassandraMailboxRecentDAOTest.java        | 32 +++++++++++-----------
 4 files changed, 30 insertions(+), 26 deletions(-)

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 0865d83..2a2dc63 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
@@ -550,7 +550,7 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
         }
 
         @Test
-        void deleteMailboxShouldCleanupACLWhenRightDeleteFails(CassandraCluster cassandraCluster) throws Exception {
+        void deleteMailboxShouldCleanupACLWhenRightsDeleteFails(CassandraCluster cassandraCluster) throws Exception {
             mailboxManager.setRights(inboxId, new MailboxACL(
                 Pair.of(MailboxACL.EntryKey.createUserEntryKey(BOB), new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read))), session);
 
@@ -654,7 +654,8 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             assertThat(deletedMessageDAO(cassandraCluster).retrieveDeletedMessage((CassandraId) inboxId, MessageRange.all())
-                .collectList().block())
+                    .collectList()
+                    .block())
                 .isEmpty();
         }
 
@@ -671,7 +672,8 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             assertThat(deletedMessageDAO(cassandraCluster).retrieveDeletedMessage((CassandraId) inboxId, MessageRange.all())
-                .collectList().block())
+                    .collectList()
+                    .block())
                 .isEmpty();
         }
 
@@ -683,7 +685,7 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             assertThat(countersDAO(cassandraCluster).retrieveMailboxCounters((CassandraId) inboxId)
-                .blockOptional())
+                    .blockOptional())
                 .isEmpty();
         }
 
@@ -699,7 +701,7 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             assertThat(countersDAO(cassandraCluster).retrieveMailboxCounters((CassandraId) inboxId)
-                .blockOptional())
+                    .blockOptional())
                 .isEmpty();
         }
 
@@ -712,7 +714,8 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             assertThat(new CassandraMailboxRecentsDAO(cassandraCluster.getConf()).getRecentMessageUidsInMailbox((CassandraId) inboxId)
-                .collectList().block())
+                    .collectList()
+                    .block())
                 .isEmpty();
         }
 
@@ -730,7 +733,8 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
             mailboxManager.deleteMailbox(inbox, session);
 
             assertThat(new CassandraMailboxRecentsDAO(cassandraCluster.getConf()).getRecentMessageUidsInMailbox((CassandraId) inboxId)
-                .collectList().block())
+                    .collectList()
+                    .block())
                 .isEmpty();
         }
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAOTest.java
index 710f400..60bbbf9 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAOTest.java
@@ -74,7 +74,7 @@ class CassandraApplicableFlagDAOTest {
     }
 
     @Test
-    void retrieveApplicableFlagShouldReturnEmptyWhenDeleted() {
+    void retrieveApplicableFlagsShouldReturnEmptyWhenDeleted() {
         testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).block();
 
         testee.delete(CASSANDRA_ID).block();
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAOTest.java
index f3154fe..87cc6a4 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAOTest.java
@@ -84,8 +84,8 @@ class CassandraDeletedMessageDAOTest {
         testee.removeAll(MAILBOX_ID).block();
 
         List<MessageUid> result = testee.retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-                .collectList()
-                .block();
+            .collectList()
+            .block();
 
         assertThat(result).isEmpty();
     }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentDAOTest.java
index e773083..e11bf82 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentDAOTest.java
@@ -51,8 +51,8 @@ class CassandraMailboxRecentDAOTest {
     @Test
     void getRecentMessageUidsInMailboxShouldBeEmptyByDefault() {
         assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
-            .collectList()
-            .block())
+                .collectList()
+                .block())
             .isEmpty();
     }
 
@@ -61,8 +61,8 @@ class CassandraMailboxRecentDAOTest {
         testee.addToRecent(CASSANDRA_ID, UID1).block();
 
         assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
-            .collectList()
-            .block())
+                .collectList()
+                .block())
             .containsOnly(UID1);
     }
 
@@ -73,8 +73,8 @@ class CassandraMailboxRecentDAOTest {
         testee.removeFromRecent(CASSANDRA_ID, UID1).block();
 
         assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
-            .collectList()
-            .block())
+                .collectList()
+                .block())
             .isEmpty();
     }
 
@@ -86,8 +86,8 @@ class CassandraMailboxRecentDAOTest {
         testee.delete(CASSANDRA_ID).block();
 
         assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
-            .collectList()
-            .block())
+                .collectList()
+                .block())
             .isEmpty();
     }
 
@@ -101,8 +101,8 @@ class CassandraMailboxRecentDAOTest {
         testee.removeFromRecent(CASSANDRA_ID, UID1).block();
 
         assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
-            .collectList()
-            .block())
+                .collectList()
+                .block())
             .isEmpty();
     }
 
@@ -113,8 +113,8 @@ class CassandraMailboxRecentDAOTest {
         testee.addToRecent(CASSANDRA_ID, UID2).block();
 
         assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
-            .collectList()
-            .block())
+                .collectList()
+                .block())
             .containsOnly(UID1, UID2);
     }
 
@@ -126,8 +126,8 @@ class CassandraMailboxRecentDAOTest {
         testee.removeFromRecent(CASSANDRA_ID, UID2).block();
 
         assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
-            .collectList()
-            .block())
+                .collectList()
+                .block())
             .containsOnly(UID1);
     }
 
@@ -151,8 +151,8 @@ class CassandraMailboxRecentDAOTest {
             .forEach(i -> testee.addToRecent(CASSANDRA_ID, MessageUid.of(i + 1)).block());
 
         assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
-            .collectList()
-            .block())
+                .collectList()
+                .block())
             .hasSize(size);
     }
 }


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