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 ma...@apache.org on 2019/01/28 14:53:16 UTC

[01/12] james-project git commit: JAMES-2630 Set CassandraAsyncExecutor.executeReactor to defer to ensure composability

Repository: james-project
Updated Branches:
  refs/heads/master df5d678cd -> e061ccb5c


JAMES-2630 Set CassandraAsyncExecutor.executeReactor to defer to ensure composability


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/ddb82362
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/ddb82362
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/ddb82362

Branch: refs/heads/master
Commit: ddb82362177c54ad27ebff98cccf3436b4348446
Parents: df5d678
Author: Gautier DI FOLCO <gd...@linagora.com>
Authored: Fri Jan 18 16:53:12 2019 +0100
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Mon Jan 28 15:30:13 2019 +0100

----------------------------------------------------------------------
 .../james/backends/cassandra/utils/CassandraAsyncExecutor.java   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/ddb82362/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
index f1084f7..decfeda 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
@@ -65,9 +65,9 @@ public class CassandraAsyncExecutor {
     }
 
     public Mono<ResultSet> executeReactor(Statement statement) {
-        return Mono.fromFuture(FutureConverter
+        return Mono.defer(() -> Mono.fromFuture(FutureConverter
                 .toCompletableFuture(session.executeAsync(statement)))
-                .publishOn(Schedulers.elastic());
+                .publishOn(Schedulers.elastic()));
     }
 
 


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


[06/12] james-project git commit: JAMES-2630 Migrate CassandraAsyncExecutor.executeReturnExists consumers to Reactor contd

Posted by ma...@apache.org.
JAMES-2630 Migrate CassandraAsyncExecutor.executeReturnExists consumers to Reactor contd


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/06ee1e43
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/06ee1e43
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/06ee1e43

Branch: refs/heads/master
Commit: 06ee1e430335693a13ee7682c98ed093e17bcd2a
Parents: 1295a89
Author: Gautier DI FOLCO <gd...@linagora.com>
Authored: Thu Dec 13 13:57:28 2018 +0100
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Mon Jan 28 15:31:00 2019 +0100

----------------------------------------------------------------------
 .../cassandra/utils/CassandraAsyncExecutor.java |   2 +-
 .../cassandra/utils/CassandraUtils.java         |   5 +
 .../mail/CassandraApplicableFlagDAO.java        |  16 +-
 .../mail/CassandraDeletedMessageDAO.java        |  39 ++-
 .../cassandra/mail/CassandraFirstUnseenDAO.java |  18 +-
 .../mail/CassandraIndexTableHandler.java        |  91 +++---
 .../mail/CassandraMailboxCounterDAO.java        |  42 ++-
 .../mail/CassandraMailboxRecentsDAO.java        |  23 +-
 .../mail/CassandraMessageIdMapper.java          |  13 +-
 .../cassandra/mail/CassandraMessageMapper.java  |  89 +++---
 .../mail/CassandraApplicableFlagDAOTest.java    |  46 ++--
 .../mail/CassandraDeletedMessageDAOTest.java    |  86 +++---
 .../mail/CassandraFirstUnseenDAOTest.java       |  66 ++---
 .../mail/CassandraIndexTableHandlerTest.java    | 274 +++++++++----------
 .../mail/CassandraMailboxCounterDAOTest.java    |  90 +++---
 .../mail/CassandraMailboxRecentDAOTest.java     |  74 +++--
 .../routes/CassandraMailboxMergingRoutes.java   |   2 +-
 17 files changed, 486 insertions(+), 490 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
index 61bd6f9..899635e 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
@@ -88,7 +88,7 @@ public class CassandraAsyncExecutor {
             .map(resultSet -> Optional.ofNullable(resultSet.one()));
     }
 
-    public Mono<Boolean> executeReturnExistsReactor(Statement statement) {
+    public Mono<Boolean> executeReturnExists(Statement statement) {
         return executeSingleRowReactor(statement)
                 .hasElement();
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraUtils.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraUtils.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraUtils.java
index fa749e6..6732966 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraUtils.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraUtils.java
@@ -28,6 +28,7 @@ import org.apache.james.backends.cassandra.init.configuration.CassandraConfigura
 
 import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Row;
+import reactor.core.publisher.Flux;
 
 public class CassandraUtils {
 
@@ -40,6 +41,10 @@ public class CassandraUtils {
         this.cassandraConfiguration = cassandraConfiguration;
     }
 
+    public Flux<Row> convertToFlux(ResultSet resultSet) {
+        return Flux.fromIterable(resultSet);
+    }
+
     public Stream<Row> convertToStream(ResultSet resultSet) {
         return StreamSupport.stream(resultSet.spliterator(), true)
             .peek(row -> ensureFetchedNextPage(resultSet));

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAO.java
----------------------------------------------------------------------
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 eed9857..4820e83 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
@@ -29,9 +29,7 @@ import static org.apache.james.mailbox.cassandra.table.CassandraApplicableFlagTa
 import static org.apache.james.mailbox.cassandra.table.CassandraApplicableFlagTable.TABLE_NAME;
 import static org.apache.james.mailbox.cassandra.table.Flag.USER_FLAGS;
 
-import java.util.Optional;
 import java.util.Set;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 import javax.mail.Flags;
@@ -43,6 +41,7 @@ import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.querybuilder.Update;
 import com.datastax.driver.core.querybuilder.Update.Assignments;
+import reactor.core.publisher.Mono;
 
 public class CassandraApplicableFlagDAO {
 
@@ -61,19 +60,18 @@ public class CassandraApplicableFlagDAO {
             .where(eq(MAILBOX_ID, bindMarker(MAILBOX_ID))));
     }
 
-    public CompletableFuture<Optional<Flags>> retrieveApplicableFlag(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    public Mono<Flags> retrieveApplicableFlag(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeSingleRowReactor(
             select.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()))
-            .thenApply(rowOptional ->
-                rowOptional.map(row -> new FlagsExtractor(row).getApplicableFlags()));
+            .map(row -> new FlagsExtractor(row).getApplicableFlags());
     }
 
-    public CompletableFuture<Void> updateApplicableFlags(CassandraId cassandraId, Set<String> toBeAdded) {
+    public Mono<Void> updateApplicableFlags(CassandraId cassandraId, Set<String> toBeAdded) {
         if (toBeAdded.isEmpty()) {
-            return CompletableFuture.completedFuture(null);
+            return Mono.empty();
         }
-        return cassandraAsyncExecutor.executeVoid(updateQuery(cassandraId, toBeAdded));
+        return cassandraAsyncExecutor.executeVoidReactor(updateQuery(cassandraId, toBeAdded));
     }
 
     private Update.Where updateQuery(CassandraId cassandraId, Set<String> userFlags) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAO.java
----------------------------------------------------------------------
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 4c6ebd9..4b5da30 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
@@ -30,9 +30,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraDeletedMessageTa
 import static org.apache.james.mailbox.cassandra.table.CassandraDeletedMessageTable.TABLE_NAME;
 import static org.apache.james.mailbox.cassandra.table.CassandraDeletedMessageTable.UID;
 
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
@@ -45,6 +42,8 @@ import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Session;
 import com.google.common.annotations.VisibleForTesting;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraDeletedMessageDAO {
     private static final String UID_TO = "uid_to";
@@ -118,25 +117,25 @@ public class CassandraDeletedMessageDAO {
             .value(UID, bindMarker(UID)));
     }
 
-    public CompletableFuture<Void> addDeleted(CassandraId cassandraId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeVoid(
+    public Mono<Void> addDeleted(CassandraId cassandraId, MessageUid uid) {
+        return cassandraAsyncExecutor.executeVoidReactor(
             addStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())
                 .setLong(UID, uid.asLong()));
     }
 
-    public CompletableFuture<Void> removeDeleted(CassandraId cassandraId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeVoid(deleteStatement.bind()
+    public Mono<Void> removeDeleted(CassandraId cassandraId, MessageUid uid) {
+        return cassandraAsyncExecutor.executeVoidReactor(deleteStatement.bind()
             .setUUID(MAILBOX_ID, cassandraId.asUuid())
             .setLong(UID, uid.asLong()));
     }
 
-    public CompletableFuture<Stream<MessageUid>> retrieveDeletedMessage(CassandraId cassandraId, MessageRange range) {
+    public Flux<MessageUid> retrieveDeletedMessage(CassandraId cassandraId, MessageRange range) {
         return retrieveResultSetOfDeletedMessage(cassandraId, range)
-            .thenApply(this::resultSetToStream);
+            .flatMapMany(this::resultSetToFlux);
     }
 
-    private CompletableFuture<ResultSet> retrieveResultSetOfDeletedMessage(CassandraId cassandraId, MessageRange range) {
+    private Mono<ResultSet> retrieveResultSetOfDeletedMessage(CassandraId cassandraId, MessageRange range) {
         switch (range.getType()) {
             case ALL:
                 return retrieveAllDeleted(cassandraId);
@@ -151,35 +150,35 @@ public class CassandraDeletedMessageDAO {
         throw new UnsupportedOperationException();
     }
 
-    private Stream<MessageUid> resultSetToStream(ResultSet resultSet) {
-        return cassandraUtils.convertToStream(resultSet)
+    private Flux<MessageUid> resultSetToFlux(ResultSet resultSet) {
+        return cassandraUtils.convertToFlux(resultSet)
             .map(row ->
                 MessageUid.of(row.getLong(UID)));
     }
 
-    private CompletableFuture<ResultSet> retrieveAllDeleted(CassandraId cassandraId) {
-        return cassandraAsyncExecutor.execute(
+    private Mono<ResultSet> retrieveAllDeleted(CassandraId cassandraId) {
+        return cassandraAsyncExecutor.executeReactor(
             selectAllUidStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid()));
     }
 
-    private CompletableFuture<ResultSet> retrieveOneDeleted(CassandraId cassandraId, MessageUid uid) {
-        return cassandraAsyncExecutor.execute(
+    private Mono<ResultSet> retrieveOneDeleted(CassandraId cassandraId, MessageUid uid) {
+        return cassandraAsyncExecutor.executeReactor(
             selectOneUidStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())
                 .setLong(UID, uid.asLong()));
     }
 
-    private CompletableFuture<ResultSet> retrieveDeletedBetween(CassandraId cassandraId, MessageUid from, MessageUid to) {
-        return cassandraAsyncExecutor.execute(
+    private Mono<ResultSet> retrieveDeletedBetween(CassandraId cassandraId, MessageUid from, MessageUid to) {
+        return cassandraAsyncExecutor.executeReactor(
             selectBetweenUidStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())
                 .setLong(UID_FROM, from.asLong())
                 .setLong(UID_TO, to.asLong()));
     }
 
-    private CompletableFuture<ResultSet> retrieveDeletedAfter(CassandraId cassandraId, MessageUid from) {
-        return cassandraAsyncExecutor.execute(
+    private Mono<ResultSet> retrieveDeletedAfter(CassandraId cassandraId, MessageUid from) {
+        return cassandraAsyncExecutor.executeReactor(
             selectFromUidStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())
                 .setLong(UID_FROM, from.asLong()));

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAO.java
----------------------------------------------------------------------
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 e710e69..50ec510 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
@@ -29,9 +29,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraFirstUnseenTable
 import static org.apache.james.mailbox.cassandra.table.CassandraFirstUnseenTable.TABLE_NAME;
 import static org.apache.james.mailbox.cassandra.table.CassandraFirstUnseenTable.UID;
 
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
@@ -40,6 +37,7 @@ import org.apache.james.mailbox.cassandra.ids.CassandraId;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
+import reactor.core.publisher.Mono;
 
 public class CassandraFirstUnseenDAO {
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
@@ -76,24 +74,24 @@ public class CassandraFirstUnseenDAO {
             .value(UID, bindMarker(UID)));
     }
 
-    public CompletableFuture<Void> addUnread(CassandraId cassandraId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeVoid(
+    public Mono<Void> addUnread(CassandraId cassandraId, MessageUid uid) {
+        return cassandraAsyncExecutor.executeVoidReactor(
             addStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())
                 .setLong(UID, uid.asLong()));
     }
 
-    public CompletableFuture<Void> removeUnread(CassandraId cassandraId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeVoid(deleteStatement.bind()
+    public Mono<Void> removeUnread(CassandraId cassandraId, MessageUid uid) {
+        return cassandraAsyncExecutor.executeVoidReactor(deleteStatement.bind()
             .setUUID(MAILBOX_ID, cassandraId.asUuid())
             .setLong(UID, uid.asLong()));
     }
 
-    public CompletableFuture<Optional<MessageUid>> retrieveFirstUnread(CassandraId cassandraId) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    public Mono<MessageUid> retrieveFirstUnread(CassandraId cassandraId) {
+        return cassandraAsyncExecutor.executeSingleRowReactor(
             readStatement.bind()
                 .setUUID(MAILBOX_ID, cassandraId.asUuid()))
-            .thenApply(optional -> optional.map(row -> MessageUid.of(row.getLong(UID))));
+            .map(row -> MessageUid.of(row.getLong(UID)));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandler.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandler.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandler.java
index 3f1485e..6ca3f46 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandler.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandler.java
@@ -19,8 +19,6 @@
 
 package org.apache.james.mailbox.cassandra.mail;
 
-import java.util.concurrent.CompletableFuture;
-
 import javax.inject.Inject;
 import javax.mail.Flags;
 
@@ -31,6 +29,8 @@ import org.apache.james.mailbox.model.UpdatedFlags;
 import org.apache.james.mailbox.store.mail.model.MailboxMessage;
 
 import com.google.common.collect.ImmutableSet;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraIndexTableHandler {
 
@@ -53,116 +53,121 @@ public class CassandraIndexTableHandler {
         this.deletedMessageDAO = deletedMessageDAO;
     }
 
-    public CompletableFuture<Void> updateIndexOnDelete(ComposedMessageIdWithMetaData composedMessageIdWithMetaData, CassandraId mailboxId) {
+    public Mono<Void> updateIndexOnDelete(ComposedMessageIdWithMetaData composedMessageIdWithMetaData, CassandraId mailboxId) {
         MessageUid uid = composedMessageIdWithMetaData.getComposedMessageId().getUid();
-        return CompletableFuture.allOf(
-            updateFirstUnseenOnDelete(mailboxId, composedMessageIdWithMetaData.getFlags(), composedMessageIdWithMetaData.getComposedMessageId().getUid()),
-            mailboxRecentDAO.removeFromRecent(mailboxId, composedMessageIdWithMetaData.getComposedMessageId().getUid()),
-            mailboxCounterDAO.decrementCount(mailboxId),
-            deletedMessageDAO.removeDeleted(mailboxId, uid),
-            decrementUnseenOnDelete(mailboxId, composedMessageIdWithMetaData.getFlags()));
+
+        return Flux.merge(
+               updateFirstUnseenOnDelete(mailboxId, composedMessageIdWithMetaData.getFlags(), composedMessageIdWithMetaData.getComposedMessageId().getUid()),
+               mailboxRecentDAO.removeFromRecent(mailboxId, composedMessageIdWithMetaData.getComposedMessageId().getUid()),
+               mailboxCounterDAO.decrementCount(mailboxId),
+               deletedMessageDAO.removeDeleted(mailboxId, uid),
+               decrementUnseenOnDelete(mailboxId, composedMessageIdWithMetaData.getFlags()))
+                .then();
     }
 
-    public CompletableFuture<Void> updateIndexOnAdd(MailboxMessage message, CassandraId mailboxId) {
+    public Mono<Void> updateIndexOnAdd(MailboxMessage message, CassandraId mailboxId) {
         Flags flags = message.createFlags();
 
-        return CompletableFuture.allOf(
-            checkDeletedOnAdd(mailboxId, message.createFlags(), message.getUid()),
-            updateFirstUnseenOnAdd(mailboxId, message.createFlags(), message.getUid()),
-            addRecentOnSave(mailboxId, message),
-            incrementUnseenOnSave(mailboxId, flags),
-            mailboxCounterDAO.incrementCount(mailboxId),
-            applicableFlagDAO.updateApplicableFlags(mailboxId, ImmutableSet.copyOf(flags.getUserFlags())));
+        return Flux.merge(
+               checkDeletedOnAdd(mailboxId, message.createFlags(), message.getUid()),
+               updateFirstUnseenOnAdd(mailboxId, message.createFlags(), message.getUid()),
+               addRecentOnSave(mailboxId, message),
+               incrementUnseenOnSave(mailboxId, flags),
+               mailboxCounterDAO.incrementCount(mailboxId),
+               applicableFlagDAO.updateApplicableFlags(mailboxId, ImmutableSet.copyOf(flags.getUserFlags())))
+                .then();
     }
 
-    public CompletableFuture<Void> updateIndexOnFlagsUpdate(CassandraId mailboxId, UpdatedFlags updatedFlags) {
-        return CompletableFuture.allOf(manageUnseenMessageCountsOnFlagsUpdate(mailboxId, updatedFlags),
-                                       manageRecentOnFlagsUpdate(mailboxId, updatedFlags),
-                                       updateFirstUnseenOnFlagsUpdate(mailboxId, updatedFlags),
-                                       applicableFlagDAO.updateApplicableFlags(mailboxId, ImmutableSet.copyOf(updatedFlags.userFlagIterator())),
-                                       updateDeletedOnFlagsUpdate(mailboxId, updatedFlags));
+    public Mono<Void> updateIndexOnFlagsUpdate(CassandraId mailboxId, UpdatedFlags updatedFlags) {
+        return Flux.merge(
+               manageUnseenMessageCountsOnFlagsUpdate(mailboxId, updatedFlags),
+               manageRecentOnFlagsUpdate(mailboxId, updatedFlags),
+               updateFirstUnseenOnFlagsUpdate(mailboxId, updatedFlags),
+               applicableFlagDAO.updateApplicableFlags(mailboxId, ImmutableSet.copyOf(updatedFlags.userFlagIterator())),
+               updateDeletedOnFlagsUpdate(mailboxId, updatedFlags))
+                .then();
     }
 
-    private CompletableFuture<Void> updateDeletedOnFlagsUpdate(CassandraId mailboxId, UpdatedFlags updatedFlags) {
+    private Mono<Void> updateDeletedOnFlagsUpdate(CassandraId mailboxId, UpdatedFlags updatedFlags) {
         if (updatedFlags.isModifiedToSet(Flags.Flag.DELETED)) {
             return deletedMessageDAO.addDeleted(mailboxId, updatedFlags.getUid());
         } else if (updatedFlags.isModifiedToUnset(Flags.Flag.DELETED)) {
             return deletedMessageDAO.removeDeleted(mailboxId, updatedFlags.getUid());
         } else {
-            return CompletableFuture.completedFuture(null);
+            return Mono.empty();
         }
     }
 
-    private CompletableFuture<Void> decrementUnseenOnDelete(CassandraId mailboxId, Flags flags) {
+    private Mono<Void> decrementUnseenOnDelete(CassandraId mailboxId, Flags flags) {
         if (flags.contains(Flags.Flag.SEEN)) {
-            return CompletableFuture.completedFuture(null);
+            return Mono.empty();
         }
         return mailboxCounterDAO.decrementUnseen(mailboxId);
     }
 
-    private CompletableFuture<Void> incrementUnseenOnSave(CassandraId mailboxId, Flags flags) {
+    private Mono<Void> incrementUnseenOnSave(CassandraId mailboxId, Flags flags) {
         if (flags.contains(Flags.Flag.SEEN)) {
-            return CompletableFuture.completedFuture(null);
+            return Mono.empty();
         }
         return mailboxCounterDAO.incrementUnseen(mailboxId);
     }
 
-    private CompletableFuture<Void> addRecentOnSave(CassandraId mailboxId, MailboxMessage message) {
+    private Mono<Void> addRecentOnSave(CassandraId mailboxId, MailboxMessage message) {
         if (message.createFlags().contains(Flags.Flag.RECENT)) {
             return mailboxRecentDAO.addToRecent(mailboxId, message.getUid());
         }
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
-    private CompletableFuture<Void> manageUnseenMessageCountsOnFlagsUpdate(CassandraId mailboxId, UpdatedFlags updatedFlags) {
+    private Mono<Void> manageUnseenMessageCountsOnFlagsUpdate(CassandraId mailboxId, UpdatedFlags updatedFlags) {
         if (updatedFlags.isModifiedToUnset(Flags.Flag.SEEN)) {
             return mailboxCounterDAO.incrementUnseen(mailboxId);
         }
         if (updatedFlags.isModifiedToSet(Flags.Flag.SEEN)) {
             return mailboxCounterDAO.decrementUnseen(mailboxId);
         }
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
-    private CompletableFuture<Void> manageRecentOnFlagsUpdate(CassandraId mailboxId, UpdatedFlags updatedFlags) {
+    private Mono<Void> manageRecentOnFlagsUpdate(CassandraId mailboxId, UpdatedFlags updatedFlags) {
         if (updatedFlags.isModifiedToUnset(Flags.Flag.RECENT)) {
             return mailboxRecentDAO.removeFromRecent(mailboxId, updatedFlags.getUid());
         }
         if (updatedFlags.isModifiedToSet(Flags.Flag.RECENT)) {
             return mailboxRecentDAO.addToRecent(mailboxId, updatedFlags.getUid());
         }
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
-    private CompletableFuture<Void> updateFirstUnseenOnAdd(CassandraId mailboxId, Flags flags, MessageUid uid) {
+    private Mono<Void> updateFirstUnseenOnAdd(CassandraId mailboxId, Flags flags, MessageUid uid) {
         if (flags.contains(Flags.Flag.SEEN)) {
-            return CompletableFuture.completedFuture(null);
+            return Mono.empty();
         }
         return firstUnseenDAO.addUnread(mailboxId, uid);
     }
 
-    private CompletableFuture<Void> checkDeletedOnAdd(CassandraId mailboxId, Flags flags, MessageUid uid) {
+    private Mono<Void> checkDeletedOnAdd(CassandraId mailboxId, Flags flags, MessageUid uid) {
         if (flags.contains(Flags.Flag.DELETED)) {
             return deletedMessageDAO.addDeleted(mailboxId, uid);
         }
 
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
-    private CompletableFuture<Void> updateFirstUnseenOnDelete(CassandraId mailboxId, Flags flags, MessageUid uid) {
+    private Mono<Void> updateFirstUnseenOnDelete(CassandraId mailboxId, Flags flags, MessageUid uid) {
         if (flags.contains(Flags.Flag.SEEN)) {
-            return CompletableFuture.completedFuture(null);
+            return Mono.empty();
         }
         return firstUnseenDAO.removeUnread(mailboxId, uid);
     }
 
-    private CompletableFuture<Void> updateFirstUnseenOnFlagsUpdate(CassandraId mailboxId, UpdatedFlags updatedFlags) {
+    private Mono<Void> updateFirstUnseenOnFlagsUpdate(CassandraId mailboxId, UpdatedFlags updatedFlags) {
         if (updatedFlags.isModifiedToUnset(Flags.Flag.SEEN)) {
             return firstUnseenDAO.addUnread(mailboxId, updatedFlags.getUid());
         }
         if (updatedFlags.isModifiedToSet(Flags.Flag.SEEN)) {
             return firstUnseenDAO.removeUnread(mailboxId, updatedFlags.getUid());
         }
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAO.java
----------------------------------------------------------------------
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 f2e2fce..5f2dec0 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
@@ -26,9 +26,6 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.incr;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.update;
 
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
@@ -42,6 +39,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 reactor.core.publisher.Mono;
 
 public class CassandraMailboxCounterDAO {
 
@@ -76,48 +74,48 @@ public class CassandraMailboxCounterDAO {
                 .where(eq(CassandraMailboxCountersTable.MAILBOX_ID, bindMarker(CassandraMailboxCountersTable.MAILBOX_ID))));
     }
 
-    public CompletableFuture<Optional<MailboxCounters>> retrieveMailboxCounters(Mailbox mailbox) throws MailboxException {
+    public Mono<MailboxCounters> retrieveMailboxCounters(Mailbox mailbox) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
-        return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(mailboxId, readStatement))
-            .thenApply(optional -> optional.map(row ->  MailboxCounters.builder()
+        return cassandraAsyncExecutor.executeSingleRowReactor(bindWithMailbox(mailboxId, readStatement))
+            .map(row ->  MailboxCounters.builder()
                 .count(row.getLong(CassandraMailboxCountersTable.COUNT))
                 .unseen(row.getLong(CassandraMailboxCountersTable.UNSEEN))
-                .build()));
+                .build());
     }
 
-    public CompletableFuture<Optional<Long>> countMessagesInMailbox(Mailbox mailbox) throws MailboxException {
+    public Mono<Long> countMessagesInMailbox(Mailbox mailbox) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
         return countMessagesInMailbox(mailboxId);
     }
 
-    public CompletableFuture<Optional<Long>> countMessagesInMailbox(CassandraId cassandraId) {
-        return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(cassandraId, readStatement))
-            .thenApply(optional -> optional.map(row -> row.getLong(CassandraMailboxCountersTable.COUNT)));
+    public Mono<Long> countMessagesInMailbox(CassandraId cassandraId) {
+        return cassandraAsyncExecutor.executeSingleRowReactor(bindWithMailbox(cassandraId, readStatement))
+            .map(row -> row.getLong(CassandraMailboxCountersTable.COUNT));
     }
 
-    public CompletableFuture<Optional<Long>> countUnseenMessagesInMailbox(Mailbox mailbox) throws MailboxException {
+    public Mono<Long> countUnseenMessagesInMailbox(Mailbox mailbox) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
-        return cassandraAsyncExecutor.executeSingleRow(bindWithMailbox(mailboxId, readStatement))
-            .thenApply(optional -> optional.map(row -> row.getLong(CassandraMailboxCountersTable.UNSEEN)));
+        return cassandraAsyncExecutor.executeSingleRowReactor(bindWithMailbox(mailboxId, readStatement))
+            .map(row -> row.getLong(CassandraMailboxCountersTable.UNSEEN));
     }
 
-    public CompletableFuture<Void> decrementCount(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, decrementMessageCountStatement));
+    public Mono<Void> decrementCount(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeVoidReactor(bindWithMailbox(mailboxId, decrementMessageCountStatement));
     }
 
-    public CompletableFuture<Void> incrementCount(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, incrementMessageCountStatement));
+    public Mono<Void> incrementCount(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeVoidReactor(bindWithMailbox(mailboxId, incrementMessageCountStatement));
     }
 
-    public CompletableFuture<Void> decrementUnseen(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, decrementUnseenCountStatement));
+    public Mono<Void> decrementUnseen(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeVoidReactor(bindWithMailbox(mailboxId, decrementUnseenCountStatement));
     }
 
-    public CompletableFuture<Void> incrementUnseen(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeVoid(bindWithMailbox(mailboxId, incrementUnseenCountStatement));
+    public Mono<Void> incrementUnseen(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeVoidReactor(bindWithMailbox(mailboxId, incrementUnseenCountStatement));
     }
 
     private BoundStatement bindWithMailbox(CassandraId mailboxId, PreparedStatement statement) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentsDAO.java
----------------------------------------------------------------------
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 2018e0b..9a521d0 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
@@ -25,9 +25,6 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
 
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
@@ -40,6 +37,8 @@ import com.datastax.driver.core.BoundStatement;
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
 import com.google.common.annotations.VisibleForTesting;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraMailboxRecentsDAO {
 
@@ -85,11 +84,11 @@ public class CassandraMailboxRecentsDAO {
                 .value(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID, bindMarker(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID)));
     }
 
-    public CompletableFuture<Stream<MessageUid>> getRecentMessageUidsInMailbox(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.execute(bindWithMailbox(mailboxId, readStatement))
-            .thenApply(cassandraUtils::convertToStream)
-            .thenApply(stream -> stream.map(row -> row.getLong(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID)))
-            .thenApply(stream -> stream.map(MessageUid::of));
+    public Flux<MessageUid> getRecentMessageUidsInMailbox(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeReactor(bindWithMailbox(mailboxId, readStatement))
+            .flatMapMany(cassandraUtils::convertToFlux)
+            .map(row -> row.getLong(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID))
+            .map(MessageUid::of);
     }
 
     private BoundStatement bindWithMailbox(CassandraId mailboxId, PreparedStatement statement) {
@@ -97,14 +96,14 @@ public class CassandraMailboxRecentsDAO {
             .setUUID(CassandraMailboxRecentsTable.MAILBOX_ID, mailboxId.asUuid());
     }
 
-    public CompletableFuture<Void> removeFromRecent(CassandraId mailboxId, MessageUid messageUid) {
-        return cassandraAsyncExecutor.executeVoid(deleteStatement.bind()
+    public Mono<Void> removeFromRecent(CassandraId mailboxId, MessageUid messageUid) {
+        return cassandraAsyncExecutor.executeVoidReactor(deleteStatement.bind()
             .setUUID(CassandraMailboxRecentsTable.MAILBOX_ID, mailboxId.asUuid())
             .setLong(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID, messageUid.asLong()));
     }
 
-    public CompletableFuture<Void> addToRecent(CassandraId mailboxId, MessageUid messageUid) {
-        return cassandraAsyncExecutor.executeVoid(addStatement.bind()
+    public Mono<Void> addToRecent(CassandraId mailboxId, MessageUid messageUid) {
+        return cassandraAsyncExecutor.executeVoidReactor(addStatement.bind()
             .setUUID(CassandraMailboxRecentsTable.MAILBOX_ID, mailboxId.asUuid())
             .setLong(CassandraMailboxRecentsTable.RECENT_MESSAGE_UID, messageUid.asLong()));
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
----------------------------------------------------------------------
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 2d9a154..880ac16 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
@@ -57,6 +57,7 @@ import org.slf4j.LoggerFactory;
 
 import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.Multimap;
+import reactor.core.publisher.Mono;
 
 public class CassandraMessageIdMapper implements MessageIdMapper {
     private static final Logger LOGGER = LoggerFactory.getLogger(CassandraMessageIdMapper.class);
@@ -150,7 +151,7 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
             .thenCompose(voidValue -> CompletableFuture.allOf(
                 imapUidDAO.insert(composedMessageIdWithMetaData),
                 messageIdDAO.insert(composedMessageIdWithMetaData)))
-            .thenCompose(voidValue -> indexTableHandler.updateIndexOnAdd(mailboxMessage, mailboxId))
+            .thenCompose(voidValue -> indexTableHandler.updateIndexOnAdd(mailboxMessage, mailboxId).toFuture())
             .join();
     }
 
@@ -162,7 +163,7 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
         CompletableFuture.allOf(
                         imapUidDAO.insert(composedMessageIdWithMetaData),
                         messageIdDAO.insert(composedMessageIdWithMetaData))
-                .thenCompose(voidValue -> indexTableHandler.updateIndexOnAdd(mailboxMessage, mailboxId))
+                .thenCompose(voidValue -> indexTableHandler.updateIndexOnAdd(mailboxMessage, mailboxId).toFuture())
                 .join();
     }
 
@@ -225,7 +226,7 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
         return CompletableFuture.allOf(
             imapUidDAO.delete(messageId, mailboxId),
             messageIdDAO.delete(mailboxId, metaData.getComposedMessageId().getUid()))
-            .thenCompose(voidValue -> indexTableHandler.updateIndexOnDelete(metaData, mailboxId));
+            .thenCompose(voidValue -> indexTableHandler.updateIndexOnDelete(metaData, mailboxId).toFuture());
     }
 
     @Override
@@ -239,7 +240,7 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
                 .isPresent())
             .flatMap(mailboxId -> flagsUpdateWithRetry(newState, updateMode, mailboxId, messageId))
             .map(this::updateCounts)
-            .map(CompletableFuture::join)
+            .map(Mono::block)
             .collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight));
     }
 
@@ -264,10 +265,10 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
         }
     }
 
-    private CompletableFuture<Pair<MailboxId, UpdatedFlags>> updateCounts(Pair<MailboxId, UpdatedFlags> pair) {
+    private Mono<Pair<MailboxId, UpdatedFlags>> updateCounts(Pair<MailboxId, UpdatedFlags> pair) {
         CassandraId cassandraId = (CassandraId) pair.getLeft();
         return indexTableHandler.updateIndexOnFlagsUpdate(cassandraId, pair.getRight())
-            .thenApply(voidValue -> pair);
+            .then(Mono.just(pair));
     }
 
     private Optional<Pair<Flags, ComposedMessageIdWithMetaData>> tryFlagsUpdate(Flags newState, MessageManager.FlagsUpdateMode updateMode, MailboxId mailboxId, MessageId messageId) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
----------------------------------------------------------------------
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 0133f05..f2b468f 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
@@ -19,7 +19,6 @@
 
 package org.apache.james.mailbox.cassandra.mail;
 
-import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
@@ -118,22 +117,22 @@ public class CassandraMessageMapper implements MessageMapper {
     @Override
     public long countMessagesInMailbox(Mailbox mailbox) throws MailboxException {
         return mailboxCounterDAO.countMessagesInMailbox(mailbox)
-            .join()
-            .orElse(0L);
+                .defaultIfEmpty(0L)
+                .block();
     }
 
     @Override
     public long countUnseenMessagesInMailbox(Mailbox mailbox) throws MailboxException {
         return mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox)
-            .join()
-            .orElse(0L);
+                .defaultIfEmpty(0L)
+                .block();
     }
 
     @Override
     public MailboxCounters getMailboxCounters(Mailbox mailbox) throws MailboxException {
         return mailboxCounterDAO.retrieveMailboxCounters(mailbox)
-            .join()
-            .orElse(INITIAL_COUNTERS);
+                .defaultIfEmpty(INITIAL_COUNTERS)
+                .block();
     }
 
     @Override
@@ -156,8 +155,7 @@ public class CassandraMessageMapper implements MessageMapper {
         return Flux.merge(
                 Mono.fromCompletionStage(imapUidDAO.delete(messageId, mailboxId)),
                 Mono.fromCompletionStage(messageIdDAO.delete(mailboxId, uid)))
-            .concatWith(Mono.fromCompletionStage(indexTableHandler.updateIndexOnDelete(composedMessageIdWithMetaData, mailboxId)))
-            .last();
+            .then(indexTableHandler.updateIndexOnDelete(composedMessageIdWithMetaData, mailboxId));
     }
 
     @Override
@@ -165,7 +163,8 @@ public class CassandraMessageMapper implements MessageMapper {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
         return retrieveMessages(retrieveMessageIds(mailboxId, messageRange), ftype, Limit.from(max))
             .map(SimpleMailboxMessage -> (MailboxMessage) SimpleMailboxMessage)
-            .sort(Comparator.comparing(MailboxMessage::getUid))
+            .collectSortedList(Comparator.comparing(MailboxMessage::getUid))
+            .flatMapMany(Flux::fromIterable)
             .toIterable()
             .iterator();
     }
@@ -189,37 +188,37 @@ public class CassandraMessageMapper implements MessageMapper {
     public List<MessageUid> findRecentMessageUidsInMailbox(Mailbox mailbox) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
         return mailboxRecentDAO.getRecentMessageUidsInMailbox(mailboxId)
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
     }
 
     @Override
     public MessageUid findFirstUnseenMessageUid(Mailbox mailbox) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
         return firstUnseenDAO.retrieveFirstUnread(mailboxId)
-            .join()
-            .orElse(null);
+                .map(Optional::of)
+                .defaultIfEmpty(Optional.empty())
+                .block()
+                .orElse(null);
     }
 
     @Override
     public Map<MessageUid, MessageMetaData> expungeMarkedForDeletionInMailbox(Mailbox mailbox, MessageRange messageRange) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
-        return Mono.fromCompletionStage(deletedMessageDAO.retrieveDeletedMessage(mailboxId, messageRange))
-            .flatMapMany(Flux::fromStream)
-            .buffer(cassandraConfiguration.getExpungeChunkSize())
-            .flatMap(uidChunk -> expungeUidChunk(mailboxId, uidChunk))
+        return deletedMessageDAO.retrieveDeletedMessage(mailboxId, messageRange)
+            .limitRate(cassandraConfiguration.getExpungeChunkSize())
+            .flatMap(messageUid -> expungeOne(mailboxId, messageUid))
             .collect(Guavate.<SimpleMailboxMessage, MessageUid, MessageMetaData>toImmutableMap(MailboxMessage::getUid, MailboxMessage::metaData))
             .block();
     }
 
-    private Flux<SimpleMailboxMessage> expungeUidChunk(CassandraId mailboxId, Collection<MessageUid> uidChunk) {
-        return Flux.fromStream(uidChunk.stream())
-            .flatMap(uid -> retrieveComposedId(mailboxId, uid))
-            .doOnNext(this::deleteUsingMailboxId)
+    private Flux<SimpleMailboxMessage> expungeOne(CassandraId mailboxId, MessageUid messageUid) {
+        return retrieveComposedId(mailboxId, messageUid)
+            .flatMap(idWithMetadata -> deleteUsingMailboxId(idWithMetadata).thenReturn(idWithMetadata))
             .flatMap(idWithMetadata ->
                 Mono.fromCompletionStage(messageDAO.retrieveMessages(ImmutableList.of(idWithMetadata), FetchType.Metadata, Limit.unlimited())))
-            .flatMap(Flux::fromStream)
+            .flatMapMany(Flux::fromStream)
             .filter(CassandraMessageDAO.MessageResult::isFound)
             .map(CassandraMessageDAO.MessageResult::message)
             .map(pair -> pair.getKey().toMailboxMessage(ImmutableList.of()));
@@ -257,7 +256,7 @@ public class CassandraMessageMapper implements MessageMapper {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
         save(mailbox, addUidAndModseq(message, mailboxId))
-            .map(voidValue -> indexTableHandler.updateIndexOnAdd(message, mailboxId))
+            .thenEmpty(indexTableHandler.updateIndexOnAdd(message, mailboxId))
             .block();
         return message.metaData();
     }
@@ -317,9 +316,10 @@ public class CassandraMessageMapper implements MessageMapper {
     private Mono<FlagsUpdateStageResult> runUpdateStage(CassandraId mailboxId, Flux<ComposedMessageIdWithMetaData> toBeUpdated, FlagsUpdateCalculator flagsUpdateCalculator) {
         Mono<Long> newModSeq = computeNewModSeq(mailboxId);
         return toBeUpdated
-            .buffer(cassandraConfiguration.getFlagsUpdateChunkSize())
-            .flatMap(uidChunk -> newModSeq.flatMap(modSeq -> performUpdatesForChunk(mailboxId, flagsUpdateCalculator, modSeq, uidChunk)))
-            .reduce(FlagsUpdateStageResult.none(), FlagsUpdateStageResult::merge);
+            .limitRate(cassandraConfiguration.getFlagsUpdateChunkSize())
+            .flatMapSequential(metadata -> newModSeq.flatMap(modSeq -> tryFlagsUpdate(flagsUpdateCalculator, modSeq, metadata)))
+            .reduce(FlagsUpdateStageResult.none(), FlagsUpdateStageResult::merge)
+            .flatMap(result -> updateIndexesForUpdatesResult(mailboxId, result));
     }
 
     private Mono<Long> computeNewModSeq(CassandraId mailboxId) {
@@ -327,23 +327,15 @@ public class CassandraMessageMapper implements MessageMapper {
             .map(value -> value.orElseThrow(() -> new RuntimeException("ModSeq generation failed for mailbox " + mailboxId.asUuid())));
     }
 
-    private Mono<FlagsUpdateStageResult> performUpdatesForChunk(CassandraId mailboxId, FlagsUpdateCalculator flagsUpdateCalculator, Long newModSeq, Collection<ComposedMessageIdWithMetaData> uidChunk) {
-        return Flux.fromIterable(uidChunk)
-            .flatMap(oldMetadata -> tryFlagsUpdate(flagsUpdateCalculator, newModSeq, oldMetadata))
-            .reduce(FlagsUpdateStageResult.none(), FlagsUpdateStageResult::merge)
-            .flatMap(result -> updateIndexesForUpdatesResult(mailboxId, result));
-    }
-
     private Mono<FlagsUpdateStageResult> updateIndexesForUpdatesResult(CassandraId mailboxId, FlagsUpdateStageResult result) {
         return Flux.fromIterable(result.getSucceeded())
             .flatMap(Throwing
-                .function((UpdatedFlags updatedFlags) -> Mono.fromCompletionStage(indexTableHandler.updateIndexOnFlagsUpdate(mailboxId, updatedFlags)))
-                .fallbackTo(failedindex -> {
-                    LOGGER.error("Could not update flag indexes for mailboxId {} UID {}. This will lead to inconsistencies across Cassandra tables", mailboxId, failedindex.getUid());
-                    return Mono.just(null);
+                .function((UpdatedFlags updatedFlags) -> indexTableHandler.updateIndexOnFlagsUpdate(mailboxId, updatedFlags))
+                .fallbackTo(failedIndex -> {
+                    LOGGER.error("Could not update flag indexes for mailboxId {} UID {}. This will lead to inconsistencies across Cassandra tables", mailboxId, failedIndex.getUid());
+                    return Mono.empty();
                 }))
-            .collectList()
-            .map(any -> result);
+            .then(Mono.just(result));
     }
 
     @Override
@@ -366,8 +358,8 @@ public class CassandraMessageMapper implements MessageMapper {
     public Flags getApplicableFlag(Mailbox mailbox) throws MailboxException {
         return ApplicableFlagBuilder.builder()
             .add(applicableFlagDAO.retrieveApplicableFlag((CassandraId) mailbox.getMailboxId())
-                .join()
-                .orElse(new Flags()))
+                .defaultIfEmpty(new Flags())
+                .block())
             .build();
     }
 
@@ -375,15 +367,15 @@ public class CassandraMessageMapper implements MessageMapper {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
         insertIds(addUidAndModseq(message, mailboxId), mailboxId)
-                .map(voidValue -> indexTableHandler.updateIndexOnAdd(message, mailboxId))
+                .thenEmpty(indexTableHandler.updateIndexOnAdd(message, mailboxId))
                 .block();
         return message.metaData();
     }
 
     private Mono<Void> save(Mailbox mailbox, MailboxMessage message) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
-        return messageDAO.save(message)
-            .flatMap(aVoid -> insertIds(message, mailboxId));
+        return Mono.fromFuture(messageDAO.save(message))
+            .thenEmpty(insertIds(message, mailboxId));
     }
 
     private Mono<Void> insertIds(MailboxMessage message, CassandraId mailboxId) {
@@ -395,7 +387,7 @@ public class CassandraMessageMapper implements MessageMapper {
         return Flux.merge(
             Mono.fromCompletionStage(messageIdDAO.insert(composedMessageIdWithMetaData)),
             Mono.fromCompletionStage(imapUidDAO.insert(composedMessageIdWithMetaData)))
-            .last();
+            .then();
     }
 
 
@@ -441,9 +433,10 @@ public class CassandraMessageMapper implements MessageMapper {
             .flatMap(success -> {
                 if (success) {
                     return Mono.fromCompletionStage(messageIdDAO.updateMetadata(newMetadata))
-                        .map(ignored -> true);
+                        .then(Mono.just(true));
                 } else {
                     return Mono.just(false);
-                }});
+                }
+            });
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraApplicableFlagDAOTest.java
----------------------------------------------------------------------
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 e2e4f62..55f7b5c 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
@@ -52,59 +52,59 @@ class CassandraApplicableFlagDAOTest {
 
     @Test
     void updateApplicableFlagsShouldReturnEmptyByDefault() {
-        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).join())
-            .isEmpty();
+        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).hasElement().block())
+            .isFalse();
     }
 
     @Test
     void updateApplicableFlagsShouldSupportEmptyUserFlags() {
-        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of()).join();
+        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of()).block();
 
-        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).join())
-            .isEmpty();
+        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).hasElement().block())
+            .isFalse();
     }
 
     @Test
     void updateApplicableFlagsShouldUpdateUserFlag() {
-        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).join();
+        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).block();
 
-        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).join())
-            .contains(new Flags(USER_FLAG));
+        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).block())
+            .isEqualTo(new Flags(USER_FLAG));
     }
 
     @Test
     void updateApplicableFlagsShouldUnionUserFlags() {
-        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).join();
-        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG2)).join();
+        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).block();
+        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG2)).block();
 
-        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).join())
-            .contains(FlagsBuilder.builder().add(USER_FLAG, USER_FLAG2).build());
+        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).block())
+            .isEqualTo(FlagsBuilder.builder().add(USER_FLAG, USER_FLAG2).build());
     }
 
     @Test
     void updateApplicableFlagsShouldBeIdempotent() {
-        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).join();
-        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).join();
+        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).block();
+        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).block();
 
-        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).join())
-            .contains(new Flags(USER_FLAG));
+        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).block())
+            .isEqualTo(new Flags(USER_FLAG));
     }
 
     @Test
     void updateApplicableFlagsShouldSkipAlreadyStoredFlagsWhenAddingFlag() {
-        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).join();
-        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG, USER_FLAG2)).join();
+        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG)).block();
+        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG, USER_FLAG2)).block();
 
-        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).join())
-            .contains(FlagsBuilder.builder().add(USER_FLAG, USER_FLAG2).build());
+        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).block())
+            .isEqualTo(FlagsBuilder.builder().add(USER_FLAG, USER_FLAG2).build());
     }
 
     @Test
     void updateApplicableFlagsShouldUpdateMultiFlags() {
-        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG, USER_FLAG2)).join();
+        testee.updateApplicableFlags(CASSANDRA_ID, ImmutableSet.of(USER_FLAG, USER_FLAG2)).block();
 
-        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).join())
-            .contains(FlagsBuilder.builder().add(USER_FLAG, USER_FLAG2).build());
+        assertThat(testee.retrieveApplicableFlag(CASSANDRA_ID).block())
+            .isEqualTo(FlagsBuilder.builder().add(USER_FLAG, USER_FLAG2).build());
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraDeletedMessageDAOTest.java
----------------------------------------------------------------------
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 906f9c7..6197506 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
@@ -34,8 +34,6 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.github.steveash.guavate.Guavate;
-
 class CassandraDeletedMessageDAOTest {
     private static final CassandraId MAILBOX_ID = CassandraId.of(UUID.fromString("110e8400-e29b-11d4-a716-446655440000"));
     private static final MessageUid UID_1 = MessageUid.of(1);
@@ -59,32 +57,32 @@ class CassandraDeletedMessageDAOTest {
     void retrieveDeletedMessageShouldReturnEmptyByDefault() {
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-            .join()
-            .collect(Guavate.toImmutableList());
+                .collectList()
+                .block();
 
         assertThat(result).isEmpty();
     }
 
     @Test
     void addDeletedMessageShouldThenBeReportedAsDeletedMessage() {
-        testee.addDeleted(MAILBOX_ID, UID_1).join();
-        testee.addDeleted(MAILBOX_ID, UID_2).join();
+        testee.addDeleted(MAILBOX_ID, UID_1).block();
+        testee.addDeleted(MAILBOX_ID, UID_2).block();
 
         List<MessageUid> result = testee.retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-            .join()
-            .collect(Guavate.toImmutableList());
+                .collectList()
+                .block();
 
         assertThat(result).containsExactly(UID_1, UID_2);
     }
 
     @Test
     void addDeletedMessageShouldBeIdempotent() {
-        testee.addDeleted(MAILBOX_ID, UID_1).join();
-        testee.addDeleted(MAILBOX_ID, UID_1).join();
+        testee.addDeleted(MAILBOX_ID, UID_1).block();
+        testee.addDeleted(MAILBOX_ID, UID_1).block();
 
         List<MessageUid> result = testee.retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).containsExactly(UID_1);
     }
@@ -92,52 +90,52 @@ class CassandraDeletedMessageDAOTest {
 
     @Test
     void removeUnreadShouldReturnEmptyWhenNoData() {
-        testee.removeDeleted(MAILBOX_ID, UID_1).join();
+        testee.removeDeleted(MAILBOX_ID, UID_1).block();
 
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).isEmpty();
     }
 
     @Test
     void removeDeletedMessageShouldNotAffectOtherMessage() {
-        testee.addDeleted(MAILBOX_ID, UID_2).join();
-        testee.addDeleted(MAILBOX_ID, UID_1).join();
+        testee.addDeleted(MAILBOX_ID, UID_2).block();
+        testee.addDeleted(MAILBOX_ID, UID_1).block();
 
-        testee.removeDeleted(MAILBOX_ID, UID_1).join();
+        testee.removeDeleted(MAILBOX_ID, UID_1).block();
 
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).containsExactly(UID_2);
     }
 
     @Test
     void removeDeletedShouldRemoveSpecifiedUID() {
-        testee.addDeleted(MAILBOX_ID, UID_2).join();
+        testee.addDeleted(MAILBOX_ID, UID_2).block();
 
-        testee.removeDeleted(MAILBOX_ID, UID_2).join();
+        testee.removeDeleted(MAILBOX_ID, UID_2).block();
 
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).isEmpty();
     }
 
     private void addMessageForRetrieveTest() {
-        testee.addDeleted(MAILBOX_ID, UID_1).join();
-        testee.addDeleted(MAILBOX_ID, UID_2).join();
-        testee.addDeleted(MAILBOX_ID, UID_3).join();
-        testee.addDeleted(MAILBOX_ID, UID_4).join();
-        testee.addDeleted(MAILBOX_ID, UID_7).join();
-        testee.addDeleted(MAILBOX_ID, UID_8).join();
+        testee.addDeleted(MAILBOX_ID, UID_1).block();
+        testee.addDeleted(MAILBOX_ID, UID_2).block();
+        testee.addDeleted(MAILBOX_ID, UID_3).block();
+        testee.addDeleted(MAILBOX_ID, UID_4).block();
+        testee.addDeleted(MAILBOX_ID, UID_7).block();
+        testee.addDeleted(MAILBOX_ID, UID_8).block();
     }
 
     @Test
@@ -146,8 +144,8 @@ class CassandraDeletedMessageDAOTest {
 
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).containsExactly(UID_1, UID_2, UID_3, UID_4, UID_7, UID_8);
     }
@@ -158,8 +156,8 @@ class CassandraDeletedMessageDAOTest {
 
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.one(UID_1))
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).containsExactly(UID_1);
     }
@@ -170,8 +168,8 @@ class CassandraDeletedMessageDAOTest {
 
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.one(MessageUid.of(42)))
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).isEmpty();
     }
@@ -182,8 +180,8 @@ class CassandraDeletedMessageDAOTest {
 
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.range(MessageUid.of(3), MessageUid.of(7)))
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).containsExactly(UID_3, UID_4, UID_7);
     }
@@ -194,8 +192,8 @@ class CassandraDeletedMessageDAOTest {
 
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.range(MessageUid.of(5), MessageUid.of(6)))
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).isEmpty();
     }
@@ -206,8 +204,8 @@ class CassandraDeletedMessageDAOTest {
 
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.from(MessageUid.of(9)))
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).isEmpty();
     }
@@ -218,8 +216,8 @@ class CassandraDeletedMessageDAOTest {
 
         List<MessageUid> result = testee
             .retrieveDeletedMessage(MAILBOX_ID, MessageRange.from(MessageUid.of(4)))
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(result).containsExactly(UID_4, UID_7, UID_8);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraFirstUnseenDAOTest.java
----------------------------------------------------------------------
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 4fae89a..882ed3c 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
@@ -47,85 +47,85 @@ class CassandraFirstUnseenDAOTest {
 
     @Test
     void retrieveFirstUnreadShouldReturnEmptyByDefault() {
-        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).join().isPresent())
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).hasElement().block())
             .isFalse();
     }
 
     @Test
     void addUnreadShouldThenBeReportedAsFirstUnseen() {
-        testee.addUnread(MAILBOX_ID, UID_1).join();
+        testee.addUnread(MAILBOX_ID, UID_1).block();
 
-        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).join())
-            .contains(UID_1);
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).block())
+            .isEqualByComparingTo(UID_1);
     }
 
     @Test
     void retrieveFirstUnreadShouldReturnLowestUnreadUid() {
-        testee.addUnread(MAILBOX_ID, UID_1).join();
+        testee.addUnread(MAILBOX_ID, UID_1).block();
 
-        testee.addUnread(MAILBOX_ID, UID_2).join();
+        testee.addUnread(MAILBOX_ID, UID_2).block();
 
-        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).join())
-            .contains(UID_1);
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).block())
+            .isEqualByComparingTo(UID_1);
     }
 
     @Test
     void retrieveFirstUnreadShouldBeOrderIndependent() {
-        testee.addUnread(MAILBOX_ID, UID_2).join();
+        testee.addUnread(MAILBOX_ID, UID_2).block();
 
-        testee.addUnread(MAILBOX_ID, UID_1).join();
+        testee.addUnread(MAILBOX_ID, UID_1).block();
 
-        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).join())
-            .contains(UID_1);
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).block())
+            .isEqualByComparingTo(UID_1);
     }
 
     @Test
     void addUnreadShouldBeIdempotent() {
-        testee.addUnread(MAILBOX_ID, UID_1).join();
+        testee.addUnread(MAILBOX_ID, UID_1).block();
 
-        testee.addUnread(MAILBOX_ID, UID_1).join();
+        testee.addUnread(MAILBOX_ID, UID_1).block();
 
-        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).join())
-            .contains(UID_1);
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).block())
+            .isEqualByComparingTo(UID_1);
     }
 
     @Test
     void removeUnreadShouldReturnWhenNoData() {
-        testee.removeUnread(MAILBOX_ID, UID_1).join();
+        testee.removeUnread(MAILBOX_ID, UID_1).block();
 
-        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).join())
-            .isEmpty();
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).hasElement().block())
+            .isFalse();
     }
 
     @Test
     void removeUnreadShouldRemoveOnlyUnread() {
-        testee.addUnread(MAILBOX_ID, UID_1).join();
+        testee.addUnread(MAILBOX_ID, UID_1).block();
 
-        testee.removeUnread(MAILBOX_ID, UID_1).join();
+        testee.removeUnread(MAILBOX_ID, UID_1).block();
 
-        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).join())
-            .isEmpty();
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).hasElement().block())
+            .isFalse();
     }
 
     @Test
     void removeUnreadShouldRemoveLastUnread() {
-        testee.addUnread(MAILBOX_ID, UID_1).join();
-        testee.addUnread(MAILBOX_ID, UID_2).join();
+        testee.addUnread(MAILBOX_ID, UID_1).block();
+        testee.addUnread(MAILBOX_ID, UID_2).block();
 
-        testee.removeUnread(MAILBOX_ID, UID_2).join();
+        testee.removeUnread(MAILBOX_ID, UID_2).block();
 
-        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).join())
-            .contains(UID_1);
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).block())
+            .isEqualByComparingTo(UID_1);
     }
 
     @Test
     void removeUnreadShouldHaveNoEffectWhenNotLast() {
-        testee.addUnread(MAILBOX_ID, UID_1).join();
-        testee.addUnread(MAILBOX_ID, UID_2).join();
+        testee.addUnread(MAILBOX_ID, UID_1).block();
+        testee.addUnread(MAILBOX_ID, UID_2).block();
 
-        testee.removeUnread(MAILBOX_ID, UID_1).join();
+        testee.removeUnread(MAILBOX_ID, UID_1).block();
 
-        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).join())
-            .contains(UID_2);
+        assertThat(testee.retrieveFirstUnread(MAILBOX_ID).block())
+            .isEqualByComparingTo(UID_2);
     }
 }


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


[12/12] james-project git commit: JAMES-2630 Improve Cassandra logging

Posted by ma...@apache.org.
JAMES-2630 Improve Cassandra logging


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/e061ccb5
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/e061ccb5
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/e061ccb5

Branch: refs/heads/master
Commit: e061ccb5c2e3fae1d0c5ff24343ffc4efd7be19a
Parents: 64d3377
Author: Matthieu Baechler <ma...@apache.org>
Authored: Fri Jan 18 11:49:50 2019 +0100
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Mon Jan 28 15:50:37 2019 +0100

----------------------------------------------------------------------
 mailbox/cassandra/src/test/resources/logback-test.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/e061ccb5/mailbox/cassandra/src/test/resources/logback-test.xml
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/resources/logback-test.xml b/mailbox/cassandra/src/test/resources/logback-test.xml
index b5e1a77..3398e17 100644
--- a/mailbox/cassandra/src/test/resources/logback-test.xml
+++ b/mailbox/cassandra/src/test/resources/logback-test.xml
@@ -7,7 +7,7 @@
 
         <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
                 <encoder>
-                        <pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
+                        <pattern>%d{HH:mm:ss.SSS} [Thread-%thread] [%-5level] %logger{15} - %msg%n%rEx</pattern>
                         <immediateFlush>false</immediateFlush>
                 </encoder>
         </appender>


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


[03/12] james-project git commit: JAMES-2630 Migrate CassandraAsyncExecutor.executeReturnExists consumers to Reactor

Posted by ma...@apache.org.
JAMES-2630 Migrate CassandraAsyncExecutor.executeReturnExists consumers to Reactor


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/9c96e60d
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/9c96e60d
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/9c96e60d

Branch: refs/heads/master
Commit: 9c96e60d8cc098da07bb49e63008a3a8fa3565fa
Parents: ddb8236
Author: Gautier DI FOLCO <gd...@linagora.com>
Authored: Wed Dec 12 14:21:46 2018 +0100
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Mon Jan 28 15:30:53 2019 +0100

----------------------------------------------------------------------
 .../james/backends/cassandra/utils/CassandraAsyncExecutor.java   | 4 ----
 .../james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java     | 4 ++--
 2 files changed, 2 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/9c96e60d/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
index decfeda..61bd6f9 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
@@ -60,10 +60,6 @@ public class CassandraAsyncExecutor {
                 .toFuture();
     }
 
-    public CompletableFuture<Boolean> executeReturnExists(Statement statement) {
-        return executeReturnExistsReactor(statement).toFuture();
-    }
-
     public Mono<ResultSet> executeReactor(Statement statement) {
         return Mono.defer(() -> Mono.fromFuture(FutureConverter
                 .toCompletableFuture(session.executeAsync(statement)))

http://git-wip-us.apache.org/repos/asf/james-project/blob/9c96e60d/server/queue/queue-rabbitmq/src/main/java/org/apache/james/queue/rabbitmq/view/cassandra/DeletedMailsDAO.java
----------------------------------------------------------------------
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 a1986e1..6d65172 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
@@ -70,10 +70,10 @@ public class DeletedMailsDAO {
     }
 
     Mono<Boolean> isDeleted(MailQueueName mailQueueName, MailKey mailKey) {
-        return Mono.fromCompletionStage(executor.executeReturnExists(
+        return executor.executeReturnExists(
             selectOne.bind()
                 .setString(QUEUE_NAME, mailQueueName.asString())
-                .setString(MAIL_KEY, mailKey.getMailKey())));
+                .setString(MAIL_KEY, mailKey.getMailKey()));
     }
 
     Mono<Boolean> isStillEnqueued(MailQueueName mailQueueName, MailKey mailKey) {


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


[02/12] james-project git commit: JAMES-2630 Migrate CassandraAsyncExecutor consumers to Reactor for event-sourcing-event-store-cassandra

Posted by ma...@apache.org.
JAMES-2630 Migrate CassandraAsyncExecutor consumers to Reactor for event-sourcing-event-store-cassandra


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/2133f0b1
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/2133f0b1
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/2133f0b1

Branch: refs/heads/master
Commit: 2133f0b1cd4362fda2f9541ccc02d4703cc3ddec
Parents: 9c96e60
Author: Gautier DI FOLCO <gd...@linagora.com>
Authored: Wed Dec 12 14:28:21 2018 +0100
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Mon Jan 28 15:30:53 2019 +0100

----------------------------------------------------------------------
 .../eventstore/cassandra/CassandraEventStore.java              | 2 +-
 .../eventsourcing/eventstore/cassandra/EventStoreDao.java      | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/2133f0b1/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStore.java
----------------------------------------------------------------------
diff --git a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStore.java b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStore.java
index 7804de1..79f6646 100644
--- a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStore.java
+++ b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/CassandraEventStore.java
@@ -51,7 +51,7 @@ public class CassandraEventStore implements EventStore {
     public void doAppendAll(List<Event> events) {
         Preconditions.checkArgument(Event.belongsToSameAggregate(events));
 
-        boolean success = eventStoreDao.appendAll(events).join();
+        boolean success = eventStoreDao.appendAll(events).block();
         if (!success) {
             throw new EventStoreFailedException("Concurrent update to the EventStore detected");
         }

http://git-wip-us.apache.org/repos/asf/james-project/blob/2133f0b1/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
----------------------------------------------------------------------
diff --git a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
index feb6ef7..e1e55c7 100644
--- a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
+++ b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
@@ -30,7 +30,6 @@ import static org.apache.james.eventsourcing.eventstore.cassandra.CassandraEvent
 
 import java.io.IOException;
 import java.util.List;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
@@ -48,6 +47,7 @@ import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.github.steveash.guavate.Guavate;
+import reactor.core.publisher.Mono;
 
 public class EventStoreDao {
     private final CassandraUtils cassandraUtils;
@@ -79,10 +79,10 @@ public class EventStoreDao {
             .where(eq(AGGREGATE_ID, bindMarker(AGGREGATE_ID))));
     }
 
-    public CompletableFuture<Boolean> appendAll(List<Event> events) {
+    public Mono<Boolean> appendAll(List<Event> events) {
         BatchStatement batch = new BatchStatement();
         events.forEach(event -> batch.add(insertEvent(event)));
-        return cassandraAsyncExecutor.executeReturnApplied(batch);
+        return cassandraAsyncExecutor.executeReturnAppliedReactor(batch);
     }
 
     private BoundStatement insertEvent(Event event) {


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


[05/12] james-project git commit: JAMES-2630 Migrate CassandraAsyncExecutor.executeReturnExists consumers to Reactor contd

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandlerTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandlerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandlerTest.java
index e504e61..fe13a9f 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandlerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraIndexTableHandlerTest.java
@@ -23,8 +23,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.util.Optional;
-
 import javax.mail.Flags;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
@@ -51,8 +49,6 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.github.steveash.guavate.Guavate;
-
 public class CassandraIndexTableHandlerTest {
 
     public static final CassandraId MAILBOX_ID = CassandraId.timeBased();
@@ -103,11 +99,10 @@ public class CassandraIndexTableHandlerTest {
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
 
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(1);
+        Long actual = mailboxCounterDAO.countMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(1);
     }
 
     @Test
@@ -116,11 +111,10 @@ public class CassandraIndexTableHandlerTest {
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
 
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(1);
+        Long actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(1);
     }
 
     @Test
@@ -129,11 +123,10 @@ public class CassandraIndexTableHandlerTest {
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.SEEN));
         when(message.getUid()).thenReturn(MESSAGE_UID);
 
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(0);
+        Long actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(0);
     }
 
     @Test
@@ -142,10 +135,11 @@ public class CassandraIndexTableHandlerTest {
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
 
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
-        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID).join()
-            .collect(Guavate.toImmutableList()))
+        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID)
+            .collectList()
+            .block())
             .isEmpty();
     }
 
@@ -155,10 +149,11 @@ public class CassandraIndexTableHandlerTest {
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.RECENT));
         when(message.getUid()).thenReturn(MESSAGE_UID);
 
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
-        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID).join()
-            .collect(Guavate.toImmutableList()))
+        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID)
+            .collectList()
+            .block())
             .containsOnly(MESSAGE_UID);
     }
 
@@ -167,17 +162,16 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(Flags.Flag.RECENT),
                 MODSEQ),
-            MAILBOX_ID).join();
+            MAILBOX_ID).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(0);
+        Long actual = mailboxCounterDAO.countMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(0);
     }
 
     @Test
@@ -185,17 +179,16 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(),
                 MODSEQ),
-            MAILBOX_ID).join();
+            MAILBOX_ID).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(0);
+        Long actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(0);
     }
 
     @Test
@@ -203,17 +196,16 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(Flags.Flag.SEEN),
                 MODSEQ),
-            MAILBOX_ID).join();
+            MAILBOX_ID).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(1);
+        Long actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(1);
     }
 
     @Test
@@ -221,16 +213,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.RECENT));
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(Flags.Flag.RECENT),
                 MODSEQ),
-            MAILBOX_ID).join();
+            MAILBOX_ID).block();
 
-        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID).join()
-            .collect(Guavate.toImmutableList()))
+        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID)
+            .collectList()
+            .block())
             .isEmpty();
     }
 
@@ -240,16 +233,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.RECENT));
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(),
                 MODSEQ),
-            MAILBOX_ID).join();
+            MAILBOX_ID).block();
 
-        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID).join()
-            .collect(Guavate.toImmutableList()))
+        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID)
+            .collectList()
+            .block())
             .isEmpty();
     }
 
@@ -257,19 +251,19 @@ public class CassandraIndexTableHandlerTest {
     void updateIndexOnDeleteShouldDeleteMessageFromDeletedMessage() {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        deletedMessageDAO.addDeleted(MAILBOX_ID, MESSAGE_UID).join();
+        deletedMessageDAO.addDeleted(MAILBOX_ID, MESSAGE_UID).block();
 
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
                 new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
                 new Flags(),
                 MODSEQ),
-            MAILBOX_ID).join();
+            MAILBOX_ID).block();
 
         assertThat(
             deletedMessageDAO
                 .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-                .join()
-                .collect(Guavate.toImmutableList()))
+                .collectList()
+                .block())
             .isEmpty();
     }
 
@@ -278,18 +272,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags(Flags.Flag.RECENT))
             .oldFlags(new Flags())
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(1);
+        Long actual = mailboxCounterDAO.countMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(1);
     }
 
     @Test
@@ -297,18 +290,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags(Flags.Flag.SEEN))
             .oldFlags(new Flags())
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(0);
+        Long actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(0);
     }
 
     @Test
@@ -316,20 +308,20 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags(Flags.Flag.DELETED))
             .oldFlags(new Flags())
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
         assertThat(
             deletedMessageDAO
                 .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-                .join()
-                .collect(Guavate.toImmutableList()))
+                .collectList()
+                .block())
             .containsExactly(MESSAGE_UID);
     }
 
@@ -338,22 +330,22 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
-        deletedMessageDAO.addDeleted(MAILBOX_ID, MESSAGE_UID).join();
+        deletedMessageDAO.addDeleted(MAILBOX_ID, MESSAGE_UID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags())
             .oldFlags(new Flags(Flags.Flag.DELETED))
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
         assertThat(
             deletedMessageDAO
                 .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-                .join()
-                .collect(Guavate.toImmutableList()))
+                .collectList()
+                .block())
             .isEmpty();
     }
 
@@ -362,22 +354,22 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
-        deletedMessageDAO.addDeleted(MAILBOX_ID, MESSAGE_UID).join();
+        deletedMessageDAO.addDeleted(MAILBOX_ID, MESSAGE_UID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags())
             .oldFlags(new Flags(Flags.Flag.SEEN))
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
         assertThat(
             deletedMessageDAO
                 .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-                .join()
-                .collect(Guavate.toImmutableList()))
+                .collectList()
+                .block())
             .containsExactly(MESSAGE_UID);
     }
 
@@ -386,20 +378,20 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags(Flags.Flag.RECENT))
             .oldFlags(new Flags())
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
         assertThat(
             deletedMessageDAO
                 .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-                .join()
-                .collect(Guavate.toImmutableList()))
+                .collectList()
+                .block())
             .isEmpty();
     }
 
@@ -408,18 +400,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.SEEN));
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags())
             .oldFlags(new Flags(Flags.Flag.SEEN))
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(1);
+        Long actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(1);
     }
 
     @Test
@@ -427,18 +418,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.SEEN));
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags(Flags.Flag.SEEN))
             .oldFlags(new Flags(Flags.Flag.SEEN))
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(0);
+        Long actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(0);
     }
 
     @Test
@@ -446,18 +436,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags())
             .oldFlags(new Flags())
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Optional<Long> actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(1);
+        Long actual = mailboxCounterDAO.countUnseenMessagesInMailbox(mailbox).block();
+        assertThat(actual).isEqualTo(1);
     }
 
     @Test
@@ -466,17 +455,18 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags(Flags.Flag.RECENT))
             .oldFlags(new Flags())
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID).join()
-            .collect(Guavate.toImmutableList()))
+        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID)
+            .collectList()
+            .block())
             .containsOnly(MESSAGE_UID);
     }
 
@@ -486,17 +476,18 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.RECENT));
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags())
             .oldFlags(new Flags(Flags.Flag.RECENT))
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID).join()
-            .collect(Guavate.toImmutableList()))
+        assertThat(mailboxRecentsDAO.getRecentMessageUidsInMailbox(MAILBOX_ID)
+            .collectList()
+            .block())
             .isEmpty();
     }
 
@@ -505,11 +496,10 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
-        Optional<MessageUid> actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(MESSAGE_UID);
+        MessageUid actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).block();
+        assertThat(actual).isEqualTo(MESSAGE_UID);
     }
 
     @Test
@@ -517,13 +507,13 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.DELETED));
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         assertThat(
             deletedMessageDAO
                 .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-                .join()
-                .collect(Guavate.toImmutableList()))
+                .collectList()
+                .block())
             .containsExactly(MESSAGE_UID);
     }
 
@@ -532,13 +522,13 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         assertThat(
             deletedMessageDAO
                 .retrieveDeletedMessage(MAILBOX_ID, MessageRange.all())
-                .join()
-                .collect(Guavate.toImmutableList()))
+                .collectList()
+                .block())
             .isEmpty();
     }
 
@@ -547,10 +537,10 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.SEEN));
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
-        Optional<MessageUid> actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).join();
-        assertThat(actual.isPresent()).isFalse();
+        Boolean actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).hasElement().block();
+        assertThat(actual).isFalse();
     }
 
     @Test
@@ -558,17 +548,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags(Flags.Flag.SEEN))
             .oldFlags(new Flags())
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Optional<MessageUid> actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).join();
-        assertThat(actual.isPresent()).isFalse();
+        Boolean actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).hasElement().block();
+        assertThat(actual).isFalse();
     }
 
     @Test
@@ -576,18 +566,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.SEEN));
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags())
             .oldFlags(new Flags(Flags.Flag.SEEN))
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Optional<MessageUid> actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(MESSAGE_UID);
+        MessageUid actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).block();
+        assertThat(actual).isEqualTo(MESSAGE_UID);
     }
 
     @Test
@@ -595,18 +584,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags())
             .oldFlags(new Flags())
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Optional<MessageUid> actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).join();
-        assertThat(actual.isPresent()).isTrue();
-        assertThat(actual.get()).isEqualTo(MESSAGE_UID);
+        MessageUid actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).block();
+        assertThat(actual).isEqualTo(MESSAGE_UID);
     }
 
     @Test
@@ -614,17 +602,17 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags(Flags.Flag.SEEN));
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags(Flags.Flag.SEEN))
             .oldFlags(new Flags(Flags.Flag.SEEN))
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Optional<MessageUid> actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).join();
-        assertThat(actual.isPresent()).isFalse();
+        Boolean actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).hasElement().block();
+        assertThat(actual).isFalse();
     }
 
     @Test
@@ -632,15 +620,15 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(new Flags());
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnDelete(new ComposedMessageIdWithMetaData(
             new ComposedMessageId(MAILBOX_ID, CASSANDRA_MESSAGE_ID, MESSAGE_UID),
             new Flags(),
-            MODSEQ), MAILBOX_ID).join();
+            MODSEQ), MAILBOX_ID).block();
 
-        Optional<MessageUid> actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).join();
-        assertThat(actual.isPresent()).isFalse();
+        Boolean actual = firstUnseenDAO.retrieveFirstUnread(MAILBOX_ID).hasElement().block();
+        assertThat(actual).isFalse();
     }
 
     @Test
@@ -649,9 +637,9 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(customFlags);
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
-        Flags applicableFlag = applicableFlagDAO.retrieveApplicableFlag(MAILBOX_ID).join().get();
+        Flags applicableFlag = applicableFlagDAO.retrieveApplicableFlag(MAILBOX_ID).block();
 
         assertThat(applicableFlag).isEqualTo(customFlags);
     }
@@ -662,7 +650,7 @@ public class CassandraIndexTableHandlerTest {
         MailboxMessage message = mock(MailboxMessage.class);
         when(message.createFlags()).thenReturn(customFlag);
         when(message.getUid()).thenReturn(MESSAGE_UID);
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         Flags customBis = new Flags("customBis");
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
@@ -670,9 +658,9 @@ public class CassandraIndexTableHandlerTest {
             .newFlags(customBis)
             .oldFlags(customFlag)
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Flags applicableFlag = applicableFlagDAO.retrieveApplicableFlag(MAILBOX_ID).join().get();
+        Flags applicableFlag = applicableFlagDAO.retrieveApplicableFlag(MAILBOX_ID).block();
 
         assertThat(applicableFlag).isEqualTo(new FlagsBuilder().add(customFlag, customBis).build());
     }
@@ -687,16 +675,16 @@ public class CassandraIndexTableHandlerTest {
         when(message.createFlags()).thenReturn(messageFlags);
         when(message.getUid()).thenReturn(MESSAGE_UID);
 
-        testee.updateIndexOnAdd(message, MAILBOX_ID).join();
+        testee.updateIndexOnAdd(message, MAILBOX_ID).block();
 
         testee.updateIndexOnFlagsUpdate(MAILBOX_ID, UpdatedFlags.builder()
             .uid(MESSAGE_UID)
             .newFlags(new Flags())
             .oldFlags(messageFlags)
             .modSeq(MODSEQ)
-            .build()).join();
+            .build()).block();
 
-        Flags applicableFlag = applicableFlagDAO.retrieveApplicableFlag(MAILBOX_ID).join().get();
+        Flags applicableFlag = applicableFlagDAO.retrieveApplicableFlag(MAILBOX_ID).block();
         assertThat(applicableFlag).isEqualTo(messageFlags);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxCounterDAOTest.java
----------------------------------------------------------------------
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 6292f98..70c0789 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
@@ -51,39 +51,39 @@ class CassandraMailboxCounterDAOTest {
 
     @Test
     void countMessagesInMailboxShouldReturnEmptyByDefault() throws Exception {
-        assertThat(testee.countMessagesInMailbox(mailbox).join()).isEmpty();
+        assertThat(testee.countMessagesInMailbox(mailbox).hasElement().block()).isFalse();
     }
 
     @Test
     void countUnseenMessagesInMailboxShouldReturnEmptyByDefault() throws Exception {
-        assertThat(testee.countUnseenMessagesInMailbox(mailbox).join()).isEmpty();
+        assertThat(testee.countUnseenMessagesInMailbox(mailbox).hasElement().block()).isFalse();
     }
 
     @Test
     void retrieveMailboxCounterShouldReturnEmptyByDefault() throws Exception {
-        assertThat(testee.retrieveMailboxCounters(mailbox).join()).isEmpty();
+        assertThat(testee.retrieveMailboxCounters(mailbox).hasElement().block()).isFalse();
     }
 
     @Test
     void incrementCountShouldAddOneWhenAbsent() throws Exception {
-        testee.incrementCount(MAILBOX_ID).join();
+        testee.incrementCount(MAILBOX_ID).block();
 
-        assertThat(testee.countMessagesInMailbox(mailbox).join()).contains(1L);
+        assertThat(testee.countMessagesInMailbox(mailbox).block()).isEqualTo(1L);
     }
 
     @Test
     void incrementUnseenShouldAddOneWhenAbsent() throws Exception {
-        testee.incrementUnseen(MAILBOX_ID).join();
+        testee.incrementUnseen(MAILBOX_ID).block();
 
-        assertThat(testee.countUnseenMessagesInMailbox(mailbox).join()).contains(1L);
+        assertThat(testee.countUnseenMessagesInMailbox(mailbox).block()).isEqualTo(1L);
     }
 
     @Test
     void incrementUnseenShouldAddOneWhenAbsentOnMailboxCounters() throws Exception {
-        testee.incrementUnseen(MAILBOX_ID).join();
+        testee.incrementUnseen(MAILBOX_ID).block();
 
-        assertThat(testee.retrieveMailboxCounters(mailbox).join())
-            .contains(MailboxCounters.builder()
+        assertThat(testee.retrieveMailboxCounters(mailbox).block())
+            .isEqualTo(MailboxCounters.builder()
                 .count(0L)
                 .unseen(1L)
                 .build());
@@ -91,10 +91,10 @@ class CassandraMailboxCounterDAOTest {
 
     @Test
     void incrementCountShouldAddOneWhenAbsentOnMailboxCounters() throws Exception {
-        testee.incrementCount(MAILBOX_ID).join();
+        testee.incrementCount(MAILBOX_ID).block();
 
-        assertThat(testee.retrieveMailboxCounters(mailbox).join())
-            .contains(MailboxCounters.builder()
+        assertThat(testee.retrieveMailboxCounters(mailbox).block())
+            .isEqualTo(MailboxCounters.builder()
                 .count(1L)
                 .unseen(0L)
                 .build());
@@ -102,11 +102,11 @@ class CassandraMailboxCounterDAOTest {
 
     @Test
     void retrieveMailboxCounterShouldWorkWhenFullRow() throws Exception {
-        testee.incrementCount(MAILBOX_ID).join();
-        testee.incrementUnseen(MAILBOX_ID).join();
+        testee.incrementCount(MAILBOX_ID).block();
+        testee.incrementUnseen(MAILBOX_ID).block();
 
-        assertThat(testee.retrieveMailboxCounters(mailbox).join())
-            .contains(MailboxCounters.builder()
+        assertThat(testee.retrieveMailboxCounters(mailbox).block())
+            .isEqualTo(MailboxCounters.builder()
                 .count(1L)
                 .unseen(1L)
                 .build());
@@ -114,73 +114,73 @@ class CassandraMailboxCounterDAOTest {
 
     @Test
     void decrementCountShouldRemoveOne() throws Exception {
-        testee.incrementCount(MAILBOX_ID).join();
+        testee.incrementCount(MAILBOX_ID).block();
 
-        testee.decrementCount(MAILBOX_ID).join();
+        testee.decrementCount(MAILBOX_ID).block();
 
-        assertThat(testee.countMessagesInMailbox(mailbox).join())
-            .contains(0L);
+        assertThat(testee.countMessagesInMailbox(mailbox).block())
+            .isEqualTo(0L);
     }
 
     @Test
     void decrementUnseenShouldRemoveOne() throws Exception {
-        testee.incrementUnseen(MAILBOX_ID).join();
+        testee.incrementUnseen(MAILBOX_ID).block();
 
-        testee.decrementUnseen(MAILBOX_ID).join();
+        testee.decrementUnseen(MAILBOX_ID).block();
 
-        assertThat(testee.countUnseenMessagesInMailbox(mailbox).join())
-            .contains(0L);
+        assertThat(testee.countUnseenMessagesInMailbox(mailbox).block())
+            .isEqualTo(0L);
     }
 
     @Test
     void incrementUnseenShouldHaveNoImpactOnMessageCount() throws Exception {
-        testee.incrementUnseen(MAILBOX_ID).join();
+        testee.incrementUnseen(MAILBOX_ID).block();
 
-        assertThat(testee.countMessagesInMailbox(mailbox).join())
-            .contains(0L);
+        assertThat(testee.countMessagesInMailbox(mailbox).block())
+            .isEqualTo(0L);
     }
 
     @Test
     void incrementCountShouldHaveNoEffectOnUnseenCount() throws Exception {
-        testee.incrementCount(MAILBOX_ID).join();
+        testee.incrementCount(MAILBOX_ID).block();
 
-        assertThat(testee.countUnseenMessagesInMailbox(mailbox).join())
-            .contains(0L);
+        assertThat(testee.countUnseenMessagesInMailbox(mailbox).block())
+            .isEqualTo(0L);
     }
 
     @Test
     void decrementUnseenShouldHaveNoEffectOnMessageCount() throws Exception {
-        testee.incrementCount(MAILBOX_ID).join();
+        testee.incrementCount(MAILBOX_ID).block();
 
-        testee.decrementUnseen(MAILBOX_ID).join();
+        testee.decrementUnseen(MAILBOX_ID).block();
 
-        assertThat(testee.countMessagesInMailbox(mailbox).join())
-            .contains(1L);
+        assertThat(testee.countMessagesInMailbox(mailbox).block())
+            .isEqualTo(1L);
     }
 
     @Test
     void decrementCountShouldHaveNoEffectOnUnseenCount() throws Exception {
-        testee.incrementUnseen(MAILBOX_ID).join();
+        testee.incrementUnseen(MAILBOX_ID).block();
 
-        testee.decrementCount(MAILBOX_ID).join();
+        testee.decrementCount(MAILBOX_ID).block();
 
-        assertThat(testee.countUnseenMessagesInMailbox(mailbox).join())
-            .contains(1L);
+        assertThat(testee.countUnseenMessagesInMailbox(mailbox).block())
+            .isEqualTo(1L);
     }
 
     @Test
     void decrementCountCanLeadToNegativeValue() throws Exception {
-        testee.decrementCount(MAILBOX_ID).join();
+        testee.decrementCount(MAILBOX_ID).block();
 
-        assertThat(testee.countMessagesInMailbox(mailbox).join())
-            .contains(-1L);
+        assertThat(testee.countMessagesInMailbox(mailbox).block())
+            .isEqualTo(-1L);
     }
 
     @Test
     void decrementUnseenCanLeadToNegativeValue() throws Exception {
-        testee.decrementUnseen(MAILBOX_ID).join();
+        testee.decrementUnseen(MAILBOX_ID).block();
 
-        assertThat(testee.countUnseenMessagesInMailbox(mailbox).join())
-            .contains(-1L);
+        assertThat(testee.countUnseenMessagesInMailbox(mailbox).block())
+            .isEqualTo(-1L);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxRecentDAOTest.java
----------------------------------------------------------------------
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 f189677..8e05300 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
@@ -32,8 +32,6 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.github.steveash.guavate.Guavate;
-
 class CassandraMailboxRecentDAOTest {
     private static final MessageUid UID1 = MessageUid.of(36L);
     private static final MessageUid UID2 = MessageUid.of(37L);
@@ -51,64 +49,78 @@ class CassandraMailboxRecentDAOTest {
 
     @Test
     void getRecentMessageUidsInMailboxShouldBeEmptyByDefault() {
-        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID).join()
-            .collect(Guavate.toImmutableList())).isEmpty();
+        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
+            .collectList()
+            .block())
+            .isEmpty();
     }
 
     @Test
     void addToRecentShouldAddUidWhenEmpty() {
-        testee.addToRecent(CASSANDRA_ID, UID1).join();
+        testee.addToRecent(CASSANDRA_ID, UID1).block();
 
-        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID).join()
-            .collect(Guavate.toImmutableList())).containsOnly(UID1);
+        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
+            .collectList()
+            .block())
+            .containsOnly(UID1);
     }
 
     @Test
     void removeFromRecentShouldRemoveUidWhenOnlyOneUid() {
-        testee.addToRecent(CASSANDRA_ID, UID1).join();
+        testee.addToRecent(CASSANDRA_ID, UID1).block();
 
-        testee.removeFromRecent(CASSANDRA_ID, UID1).join();
+        testee.removeFromRecent(CASSANDRA_ID, UID1).block();
 
-        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID).join()
-            .collect(Guavate.toImmutableList())).isEmpty();
+        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
+            .collectList()
+            .block())
+            .isEmpty();
     }
 
     @Test
     void removeFromRecentShouldNotFailIfNotExisting() {
-        testee.removeFromRecent(CASSANDRA_ID, UID1).join();
+        testee.removeFromRecent(CASSANDRA_ID, UID1).block();
 
-        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID).join()
-            .collect(Guavate.toImmutableList())).isEmpty();
+        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
+            .collectList()
+            .block())
+            .isEmpty();
     }
 
     @Test
     void addToRecentShouldAddUidWhenNotEmpty() {
-        testee.addToRecent(CASSANDRA_ID, UID1).join();
+        testee.addToRecent(CASSANDRA_ID, UID1).block();
 
-        testee.addToRecent(CASSANDRA_ID, UID2).join();
+        testee.addToRecent(CASSANDRA_ID, UID2).block();
 
-        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID).join()
-            .collect(Guavate.toImmutableList())).containsOnly(UID1, UID2);
+        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
+            .collectList()
+            .block())
+            .containsOnly(UID1, UID2);
     }
 
     @Test
     void removeFromRecentShouldOnlyRemoveUidWhenNotEmpty() {
-        testee.addToRecent(CASSANDRA_ID, UID1).join();
-        testee.addToRecent(CASSANDRA_ID, UID2).join();
+        testee.addToRecent(CASSANDRA_ID, UID1).block();
+        testee.addToRecent(CASSANDRA_ID, UID2).block();
 
-        testee.removeFromRecent(CASSANDRA_ID, UID2).join();
+        testee.removeFromRecent(CASSANDRA_ID, UID2).block();
 
-        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID).join()
-            .collect(Guavate.toImmutableList())).containsOnly(UID1);
+        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
+            .collectList()
+            .block())
+            .containsOnly(UID1);
     }
 
     @Test
     void addToRecentShouldBeIdempotent() {
-        testee.addToRecent(CASSANDRA_ID, UID1).join();
-        testee.addToRecent(CASSANDRA_ID, UID1).join();
+        testee.addToRecent(CASSANDRA_ID, UID1).block();
+        testee.addToRecent(CASSANDRA_ID, UID1).block();
 
-        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID).join()
-            .collect(Guavate.toImmutableList())).containsOnly(UID1);
+        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
+            .collectList()
+            .block())
+            .containsOnly(UID1);
     }
 
     @Test
@@ -117,9 +129,11 @@ class CassandraMailboxRecentDAOTest {
         int size = pageSize + 1000;
         IntStream.range(0, size)
             .parallel()
-            .forEach(i -> testee.addToRecent(CASSANDRA_ID, MessageUid.of(i + 1)).join());
+            .forEach(i -> testee.addToRecent(CASSANDRA_ID, MessageUid.of(i + 1)).block());
 
-        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID).join()
-            .collect(Guavate.toImmutableList())).hasSize(size);
+        assertThat(testee.getRecentMessageUidsInMailbox(CASSANDRA_ID)
+            .collectList()
+            .block())
+            .hasSize(size);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/06ee1e43/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMailboxMergingRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMailboxMergingRoutes.java b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMailboxMergingRoutes.java
index e1f3cd3..b882013 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMailboxMergingRoutes.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMailboxMergingRoutes.java
@@ -115,7 +115,7 @@ public class CassandraMailboxMergingRoutes implements Routes {
             CassandraId originId = mailboxIdFactory.fromString(mailboxMergingRequest.getMergeOrigin());
             CassandraId destinationId = mailboxIdFactory.fromString(mailboxMergingRequest.getMergeDestination());
 
-            long totalMessagesToMove = counterDAO.countMessagesInMailbox(originId).join().orElse(0L);
+            long totalMessagesToMove = counterDAO.countMessagesInMailbox(originId).defaultIfEmpty(0L).block();
             MailboxMergingTask task = new MailboxMergingTask(mailboxMergingTaskRunner, totalMessagesToMove, originId, destinationId);
             TaskId taskId = taskManager.submit(task);
             return TaskIdDto.respond(response, taskId);


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


[10/12] james-project git commit: JAMES-2630 Migrate CassandraAsyncExecutor.executeReturnApplied consumers to Reactor

Posted by ma...@apache.org.
JAMES-2630 Migrate CassandraAsyncExecutor.executeReturnApplied consumers to Reactor


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/e4a737e5
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/e4a737e5
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/e4a737e5

Branch: refs/heads/master
Commit: e4a737e52c34c217503dee3e69cc9d0275937046
Parents: 06ee1e4
Author: Gautier DI FOLCO <gd...@linagora.com>
Authored: Tue Jan 8 16:41:38 2019 +0100
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Mon Jan 28 15:49:06 2019 +0100

----------------------------------------------------------------------
 .../cassandra/utils/CassandraAsyncExecutor.java |  12 +-
 .../utils/FunctionRunnerWithRetry.java          |  78 --------
 .../utils/FunctionRunnerWithRetryTest.java      | 173 ------------------
 .../eventstore/cassandra/EventStoreDao.java     |   2 +-
 .../james/mailbox/MailboxManagerStressTest.java |   2 +-
 .../cassandra/mail/AttachmentLoader.java        |  51 ++----
 .../cassandra/mail/CassandraACLMapper.java      | 138 ++++++---------
 .../cassandra/mail/CassandraAttachmentDAO.java  |   8 +-
 .../mail/CassandraAttachmentDAOV2.java          |  13 +-
 .../mail/CassandraAttachmentMapper.java         |  87 ++++-----
 .../mail/CassandraAttachmentMessageIdDAO.java   |   5 +-
 .../mail/CassandraAttachmentOwnerDAO.java       |   5 +-
 .../cassandra/mail/CassandraMailboxDAO.java     |  32 ++--
 .../cassandra/mail/CassandraMailboxMapper.java  | 147 +++++++---------
 .../cassandra/mail/CassandraMailboxPathDAO.java |  19 +-
 .../mail/CassandraMailboxPathDAOImpl.java       |  47 ++---
 .../mail/CassandraMailboxPathV2DAO.java         |  47 +++--
 .../cassandra/mail/CassandraMessageDAO.java     |  61 +++----
 .../cassandra/mail/CassandraMessageIdDAO.java   |   9 +-
 .../mail/CassandraMessageIdMapper.java          | 176 +++++++++----------
 .../mail/CassandraMessageIdToImapUidDAO.java    |  21 +--
 .../cassandra/mail/CassandraMessageMapper.java  |  49 +++---
 .../cassandra/mail/CassandraModSeqProvider.java |  98 +++++------
 .../cassandra/mail/CassandraUidProvider.java    |  81 ++++-----
 .../mail/CassandraUserMailboxRightsDAO.java     |  42 +++--
 .../migration/AttachmentMessageIdCreation.java  |  12 +-
 .../mail/migration/AttachmentV2Migration.java   |   2 +-
 .../mail/migration/MailboxPathV2Migration.java  |   4 +-
 .../mail/task/MailboxMergingTaskRunner.java     |   8 +-
 .../cassandra/mail/AttachmentLoaderTest.java    |  82 ++-------
 .../cassandra/mail/CassandraACLMapperTest.java  |  24 +--
 .../mail/CassandraAttachmentDAOTest.java        |   6 +-
 .../mail/CassandraAttachmentDAOV2Test.java      |   6 +-
 .../mail/CassandraAttachmentFallbackTest.java   |  12 +-
 .../mail/CassandraAttachmentOwnerDAOTest.java   |  17 +-
 .../cassandra/mail/CassandraMailboxDAOTest.java |  44 +++--
 .../mail/CassandraMailboxMapperTest.java        |  88 +++++-----
 .../mail/CassandraMailboxPathDAOImplTest.java   |  12 +-
 .../mail/CassandraMailboxPathDAOTest.java       |  37 ++--
 .../cassandra/mail/CassandraMapperProvider.java |   3 +-
 .../cassandra/mail/CassandraMessageDAOTest.java |   6 +-
 .../mail/CassandraMessageIdDAOTest.java         |  24 +--
 .../CassandraMessageIdToImapUidDAOTest.java     |  95 +++++-----
 .../mail/CassandraModSeqProviderTest.java       |  27 ++-
 .../mail/CassandraUidProviderTest.java          |  26 ++-
 .../mail/CassandraUserMailboxRightsDAOTest.java |  12 +-
 .../migration/AttachmentV2MigrationTest.java    |  14 +-
 .../migration/MailboxPathV2MigrationTest.java   |  18 +-
 .../AbstractMailboxManagerAttachmentTest.java   |  23 ++-
 server/container/util/pom.xml                   |   6 +
 .../cassandra/CassandraDomainList.java          |   4 +-
 .../cassandra/CassandraActiveScriptDAO.java     |  19 +-
 .../sieve/cassandra/CassandraSieveDAO.java      |  20 +--
 .../sieve/cassandra/CassandraSieveQuotaDAO.java |   5 +-
 .../cassandra/CassandraSieveRepository.java     |  91 +++++-----
 .../cassandra/CassandraUsersRepository.java     |   6 +-
 .../cassandra/CassandraActiveScriptDAOTest.java |  22 +--
 .../sieve/cassandra/CassandraSieveDAOTest.java  |  34 ++--
 .../cassandra/CassandraSieveQuotaDAOTest.java   |  10 +-
 .../cassandra/CassandraMailRepository.java      |  47 ++---
 .../CassandraMailRepositoryCountDAO.java        |   9 +-
 .../CassandraMailRepositoryKeysDAO.java         |  17 +-
 .../CassandraMailRepositoryMailDAO.java         |   5 +-
 .../CassandraMailRepositoryMailDaoAPI.java      |   4 +-
 .../CassandraMailRepositoryMailDaoV2.java       |   6 +-
 .../MergingCassandraMailRepositoryMailDao.java  |   6 +-
 .../CassandraMailRepositoryCountDAOTest.java    |  18 +-
 .../CassandraMailRepositoryKeysDAOTest.java     |  54 +++---
 .../CassandraMailRepositoryMailDAOTest.java     |   4 +-
 ...ilRepositoryWithFakeImplementationsTest.java |  29 +--
 70 files changed, 1031 insertions(+), 1390 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
index 899635e..361bb93 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraAsyncExecutor.java
@@ -46,11 +46,6 @@ public class CassandraAsyncExecutor {
         return executeReactor(statement).toFuture();
     }
 
-
-    public CompletableFuture<Boolean> executeReturnApplied(Statement statement) {
-        return executeReturnAppliedReactor(statement).toFuture();
-    }
-
     public CompletableFuture<Void> executeVoid(Statement statement) {
         return executeVoidReactor(statement).toFuture();
     }
@@ -67,9 +62,8 @@ public class CassandraAsyncExecutor {
     }
 
 
-    public Mono<Boolean> executeReturnAppliedReactor(Statement statement) {
-        return executeReactor(statement)
-                .map(ResultSet::one)
+    public Mono<Boolean> executeReturnApplied(Statement statement) {
+        return executeSingleRowReactor(statement)
                 .map(row -> row.getBool(CassandraConstants.LIGHTWEIGHT_TRANSACTION_APPLIED));
     }
 
@@ -83,7 +77,7 @@ public class CassandraAsyncExecutor {
                 .flatMap(Mono::justOrEmpty);
     }
 
-    private Mono<Optional<Row>> executeSingleRowOptionalReactor(Statement statement) {
+    public Mono<Optional<Row>> executeSingleRowOptionalReactor(Statement statement) {
         return executeReactor(statement)
             .map(resultSet -> Optional.ofNullable(resultSet.one()));
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/FunctionRunnerWithRetry.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/FunctionRunnerWithRetry.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/FunctionRunnerWithRetry.java
deleted file mode 100644
index 86e1aba..0000000
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/FunctionRunnerWithRetry.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.backends.cassandra.utils;
-
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.BooleanSupplier;
-import java.util.function.Supplier;
-import java.util.stream.IntStream;
-
-import com.google.common.base.Preconditions;
-
-public class FunctionRunnerWithRetry {
-
-    public static class RelayingException extends RuntimeException {}
-
-    @FunctionalInterface
-    public interface OptionalSupplier<T> {
-        Optional<T> getAsOptional();
-    }
-
-    private final int maxRetry;
-
-    public FunctionRunnerWithRetry(int maxRetry) {
-        Preconditions.checkArgument(maxRetry > 0);
-        this.maxRetry = maxRetry;
-    }
-
-    public void execute(BooleanSupplier functionNotifyingSuccess) throws LightweightTransactionException {
-        IntStream.range(0, maxRetry)
-            .filter((x) -> functionNotifyingSuccess.getAsBoolean())
-            .findFirst()
-            .orElseThrow(() -> new LightweightTransactionException(maxRetry));
-    }
-
-    public <T> T executeAndRetrieveObject(OptionalSupplier<T> functionNotifyingSuccess) throws LightweightTransactionException {
-        return IntStream.range(0, maxRetry)
-            .mapToObj((x) -> functionNotifyingSuccess.getAsOptional())
-            .filter(Optional::isPresent)
-            .findFirst()
-            .orElseThrow(() -> new LightweightTransactionException(maxRetry))
-            .get();
-    }
-
-    public <T> CompletableFuture<Optional<T>> executeAsyncAndRetrieveObject(Supplier<CompletableFuture<Optional<T>>> futureSupplier) {
-        return executeAsyncAndRetrieveObject(futureSupplier, 0);
-    }
-
-    public <T> CompletableFuture<Optional<T>> executeAsyncAndRetrieveObject(Supplier<CompletableFuture<Optional<T>>> futureSupplier, int tries) {
-        if (tries >= maxRetry) {
-            return CompletableFuture.completedFuture(Optional.empty());
-        }
-        return futureSupplier.get()
-            .thenCompose(optional -> {
-                if (optional.isPresent()) {
-                    return CompletableFuture.completedFuture(optional);
-                }
-                return executeAsyncAndRetrieveObject(futureSupplier, tries + 1);
-            });
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/utils/FunctionRunnerWithRetryTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/utils/FunctionRunnerWithRetryTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/utils/FunctionRunnerWithRetryTest.java
deleted file mode 100644
index 7fe5813..0000000
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/utils/FunctionRunnerWithRetryTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.backends.cassandra.utils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.commons.lang.mutable.MutableInt;
-import org.junit.Test;
-
-public class FunctionRunnerWithRetryTest {
-    
-    private static final int MAX_RETRY = 10;
-
-    @Test(expected = IllegalArgumentException.class)
-    public void functionRunnerWithInvalidMaxRetryShouldFail() throws Exception {
-        new FunctionRunnerWithRetry(-1);
-    }
-
-    @Test(expected = LightweightTransactionException.class)
-    public void functionRunnerShouldFailIfTransactionCanNotBePerformed() throws Exception {
-        final MutableInt value = new MutableInt(0);
-        new FunctionRunnerWithRetry(MAX_RETRY).execute(
-            () -> {
-                value.increment();
-                return false;
-            }
-        );
-        assertThat(value.getValue()).isEqualTo(MAX_RETRY);
-    }
-    
-    @Test
-    public void functionRunnerShouldWorkOnFirstTry() throws Exception {
-        final MutableInt value = new MutableInt(0);
-        new FunctionRunnerWithRetry(MAX_RETRY).execute(
-            () -> {
-                value.increment();
-                return true;
-            }
-        );
-        assertThat(value.getValue()).isEqualTo(1);
-    }
-
-    @Test
-    public void functionRunnerShouldWorkIfNotSucceededOnFirstTry() throws Exception {
-        final MutableInt value = new MutableInt(0);
-        new FunctionRunnerWithRetry(MAX_RETRY).execute(
-            () -> {
-                value.increment();
-                return (Integer) value.getValue() == MAX_RETRY / 2;
-            }
-        );
-        assertThat(value.getValue()).isEqualTo(MAX_RETRY / 2);
-    }
-
-    @Test
-    public void functionRunnerShouldWorkIfNotSucceededOnMaxRetryReached() throws Exception {
-        final MutableInt value = new MutableInt(0);
-        new FunctionRunnerWithRetry(MAX_RETRY).execute(
-                () -> {
-                    value.increment();
-                    return (Integer) value.getValue() == MAX_RETRY;
-                }
-        );
-        assertThat(value.getValue()).isEqualTo(MAX_RETRY);
-    }
-
-    @Test
-    public void asyncFunctionRunnerShouldWorkIfSucceedFirstTry() throws Exception {
-        int value = 18;
-
-        Optional<Integer> result = new FunctionRunnerWithRetry(MAX_RETRY)
-            .executeAsyncAndRetrieveObject(
-                () -> CompletableFuture.completedFuture(Optional.of(value)))
-            .join();
-
-        assertThat(result).contains(value);
-    }
-
-    @Test
-    public void asyncFunctionRunnerShouldTryOnlyOnceIfSuccess() throws Exception {
-        int value = 18;
-        AtomicInteger times = new AtomicInteger(0);
-
-        new FunctionRunnerWithRetry(MAX_RETRY)
-            .executeAsyncAndRetrieveObject(
-                () -> {
-                    times.incrementAndGet();
-                    return CompletableFuture.completedFuture(Optional.of(value));
-                })
-            .join();
-
-        assertThat(times.get()).isEqualTo(1);
-    }
-
-    @Test
-    public void asyncFunctionRunnerShouldRetrieveValueOnRetry() throws Exception {
-        int value = 18;
-        AtomicInteger times = new AtomicInteger(0);
-
-        Optional<Integer> result = new FunctionRunnerWithRetry(MAX_RETRY)
-            .executeAsyncAndRetrieveObject(
-                () -> {
-                    int attemptCount = times.incrementAndGet();
-                    if (attemptCount == MAX_RETRY) {
-                        return CompletableFuture.completedFuture(Optional.of(value));
-                    } else {
-                        return CompletableFuture.completedFuture(Optional.empty());
-                    }
-                })
-            .join();
-
-        assertThat(result).contains(value);
-    }
-
-    @Test
-    public void asyncFunctionRunnerShouldMakeMaxRetryAttempts() throws Exception {
-        int value = 18;
-        AtomicInteger times = new AtomicInteger(0);
-
-        new FunctionRunnerWithRetry(MAX_RETRY)
-            .executeAsyncAndRetrieveObject(
-                () -> {
-                    int attemptCount = times.incrementAndGet();
-                    if (attemptCount == MAX_RETRY) {
-                        return CompletableFuture.completedFuture(Optional.of(value));
-                    } else {
-                        return CompletableFuture.completedFuture(Optional.empty());
-                    }
-                })
-            .join();
-
-        assertThat(times.get()).isEqualTo(MAX_RETRY);
-    }
-
-
-    @Test
-    public void asyncFunctionRunnerShouldReturnEmptyIfAllFailed() throws Exception {
-        AtomicInteger times = new AtomicInteger(0);
-
-        Optional<Integer> result = new FunctionRunnerWithRetry(MAX_RETRY)
-            .executeAsyncAndRetrieveObject(
-                () -> {
-                    times.incrementAndGet();
-                    return CompletableFuture.completedFuture(Optional.<Integer>empty());
-                })
-            .join();
-
-        assertThat(result).isEmpty();
-        assertThat(times.get()).isEqualTo(MAX_RETRY);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
----------------------------------------------------------------------
diff --git a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
index e1e55c7..8f6a9d1 100644
--- a/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
+++ b/event-sourcing/event-store-cassandra/src/main/java/org/apache/james/eventsourcing/eventstore/cassandra/EventStoreDao.java
@@ -82,7 +82,7 @@ public class EventStoreDao {
     public Mono<Boolean> appendAll(List<Event> events) {
         BatchStatement batch = new BatchStatement();
         events.forEach(event -> batch.add(insertEvent(event)));
-        return cassandraAsyncExecutor.executeReturnAppliedReactor(batch);
+        return cassandraAsyncExecutor.executeReturnApplied(batch);
     }
 
     private BoundStatement insertEvent(Event event) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressTest.java
----------------------------------------------------------------------
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressTest.java
index 97e0103..544e1fe 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressTest.java
@@ -81,7 +81,7 @@ public abstract class MailboxManagerStressTest<T extends MailboxManager> {
         final AtomicBoolean fail = new AtomicBoolean(false);
         final ConcurrentHashMap<MessageUid, Object> uids = new ConcurrentHashMap<>();
 
-        // fire of 1000 append operations
+        // fire of append operations
         for (int i = 0; i < APPEND_OPERATIONS; i++) {
             pool.execute(() -> {
                 if (fail.get()) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoader.java
----------------------------------------------------------------------
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 bf486ed..d57e99a 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
@@ -19,24 +19,18 @@
 package org.apache.james.mailbox.cassandra.mail;
 
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.Function;
 import java.util.stream.Stream;
 
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.mailbox.model.Attachment;
-import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.mailbox.store.mail.MessageMapper;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
-import org.apache.james.util.FluentFutureStream;
 
-import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class AttachmentLoader {
 
@@ -46,33 +40,23 @@ public class AttachmentLoader {
         this.attachmentMapper = attachmentMapper;
     }
 
-    public CompletableFuture<Stream<SimpleMailboxMessage>> addAttachmentToMessages(Stream<Pair<MessageWithoutAttachment,
-            Stream<MessageAttachmentRepresentation>>> messageRepresentations, MessageMapper.FetchType fetchType) {
+    public Mono<SimpleMailboxMessage> addAttachmentToMessage(Pair<MessageWithoutAttachment, Stream<MessageAttachmentRepresentation>> messageRepresentation, MessageMapper.FetchType fetchType) {
 
         if (fetchType == MessageMapper.FetchType.Body || fetchType == MessageMapper.FetchType.Full) {
-            return FluentFutureStream.<SimpleMailboxMessage>of(
-                messageRepresentations
-                    .map(pair -> getAttachments(pair.getRight().collect(Guavate.toImmutableList()))
-                        .thenApply(attachments -> pair.getLeft().toMailboxMessage(attachments))))
-                .completableFuture();
+            return getAttachments(messageRepresentation.getRight().collect(ImmutableList.toImmutableList()))
+                        .map(attachments -> messageRepresentation.getLeft().toMailboxMessage(attachments));
         } else {
-            return CompletableFuture.completedFuture(messageRepresentations
-                .map(pair -> pair.getLeft()
-                    .toMailboxMessage(ImmutableList.of())));
+            return Mono.just(messageRepresentation.getLeft().toMailboxMessage(ImmutableList.of()));
         }
     }
 
     @VisibleForTesting
-    CompletableFuture<List<MessageAttachment>> getAttachments(List<MessageAttachmentRepresentation> attachmentRepresentations) {
-        CompletableFuture<Map<AttachmentId, Attachment>> attachmentsByIdFuture =
-            attachmentsById(attachmentRepresentations.stream()
-                .map(MessageAttachmentRepresentation::getAttachmentId)
-                .collect(Guavate.toImmutableSet()));
-
-        return attachmentsByIdFuture.thenApply(attachmentsById ->
-            attachmentRepresentations.stream()
-                .map(representation -> constructMessageAttachment(attachmentsById.get(representation.getAttachmentId()), representation))
-                .collect(Guavate.toImmutableList()));
+    Mono<List<MessageAttachment>> getAttachments(List<MessageAttachmentRepresentation> attachmentRepresentations) {
+        return Flux.fromIterable(attachmentRepresentations)
+                .flatMap(attachmentRepresentation ->
+                        attachmentMapper.getAttachmentsAsMono(attachmentRepresentation.getAttachmentId())
+                            .map(attachment -> constructMessageAttachment(attachment, attachmentRepresentation)))
+                .collectList();
     }
 
     private MessageAttachment constructMessageAttachment(Attachment attachment, MessageAttachmentRepresentation messageAttachmentRepresentation) {
@@ -84,15 +68,4 @@ public class AttachmentLoader {
                 .build();
     }
 
-    @VisibleForTesting
-    CompletableFuture<Map<AttachmentId, Attachment>> attachmentsById(Set<AttachmentId> attachmentIds) {
-        if (attachmentIds.isEmpty()) {
-            return CompletableFuture.completedFuture(ImmutableMap.of());
-        }
-        return attachmentMapper.getAttachmentsAsFuture(attachmentIds)
-            .thenApply(attachments -> attachments
-                .stream()
-                .collect(Guavate.toImmutableMap(Attachment::getAttachmentId, Function.identity())));
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
----------------------------------------------------------------------
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 7f2bb6a..dd6f6cd 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
@@ -27,16 +27,12 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.set;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.update;
 
 import java.io.IOException;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 import java.util.function.Function;
 
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.backends.cassandra.utils.FunctionRunnerWithRetry;
-import org.apache.james.backends.cassandra.utils.LightweightTransactionException;
 import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
@@ -45,14 +41,15 @@ import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.UnsupportedRightException;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.store.json.MailboxACLJsonConverter;
+import org.apache.james.util.FunctionalUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.fasterxml.jackson.core.JsonProcessingException;
+import reactor.core.publisher.Mono;
 
 public class CassandraACLMapper {
     public static final int INITIAL_VALUE = 0;
@@ -65,7 +62,7 @@ public class CassandraACLMapper {
     }
 
     private final CassandraAsyncExecutor executor;
-    private final int maxRetry;
+    private final int maxAclRetry;
     private final CodeInjector codeInjector;
     private final CassandraUserMailboxRightsDAO userMailboxRightsDAO;
     private final PreparedStatement conditionalInsertStatement;
@@ -79,7 +76,7 @@ public class CassandraACLMapper {
 
     public CassandraACLMapper(Session session, CassandraUserMailboxRightsDAO userMailboxRightsDAO, CassandraConfiguration cassandraConfiguration, CodeInjector codeInjector) {
         this.executor = new CassandraAsyncExecutor(session);
-        this.maxRetry = cassandraConfiguration.getAclMaxRetry();
+        this.maxAclRetry = cassandraConfiguration.getAclMaxRetry();
         this.codeInjector = codeInjector;
         this.conditionalInsertStatement = prepareConditionalInsert(session);
         this.conditionalUpdateStatement = prepareConditionalUpdate(session);
@@ -112,103 +109,84 @@ public class CassandraACLMapper {
                 .where(eq(CassandraMailboxTable.ID, bindMarker(CassandraACLTable.ID))));
     }
 
-    public CompletableFuture<MailboxACL> getACL(CassandraId cassandraId) {
+    public Mono<MailboxACL> getACL(CassandraId cassandraId) {
         return getStoredACLRow(cassandraId)
-            .thenApply(resultSet -> getAcl(cassandraId, resultSet));
+            .map(row -> getAcl(cassandraId, row))
+            .switchIfEmpty(Mono.just(MailboxACL.EMPTY));
     }
 
-    private MailboxACL getAcl(CassandraId cassandraId, ResultSet resultSet) {
-        if (resultSet.isExhausted()) {
-            return MailboxACL.EMPTY;
-        }
-        String serializedACL = resultSet.one().getString(CassandraACLTable.ACL);
+    private MailboxACL getAcl(CassandraId cassandraId, Row row) {
+        String serializedACL = row.getString(CassandraACLTable.ACL);
         return deserializeACL(cassandraId, serializedACL);
     }
 
     public ACLDiff updateACL(CassandraId cassandraId, MailboxACL.ACLCommand command) throws MailboxException {
         MailboxACL replacement = MailboxACL.EMPTY.apply(command);
-
-        ACLDiff aclDiff = updateAcl(cassandraId, aclWithVersion -> aclWithVersion.apply(command), replacement);
-
-        return userMailboxRightsDAO.update(cassandraId, aclDiff)
-            .thenApply(any -> aclDiff)
-            .join();
+        return updateAcl(cassandraId, aclWithVersion -> aclWithVersion.apply(command), replacement)
+            .flatMap(aclDiff -> userMailboxRightsDAO.update(cassandraId, aclDiff)
+            .thenReturn(aclDiff))
+            .blockOptional()
+            .orElseThrow(() -> new MailboxException("Unable to update ACL"));
     }
 
     public ACLDiff setACL(CassandraId cassandraId, MailboxACL mailboxACL) throws MailboxException {
-        ACLDiff aclDiff = updateAcl(cassandraId,
-            acl -> new ACLWithVersion(acl.version, mailboxACL),
-            mailboxACL);
-
-        return userMailboxRightsDAO.update(cassandraId, aclDiff)
-            .thenApply(any -> aclDiff)
-            .join();
-    }
-
-    private ACLDiff updateAcl(CassandraId cassandraId, Function<ACLWithVersion, ACLWithVersion> aclTransformation, MailboxACL replacement) throws MailboxException {
-        try {
-            return new FunctionRunnerWithRetry(maxRetry)
-                .executeAndRetrieveObject(
-                    () -> {
-                        codeInjector.inject();
-                        return getAclWithVersion(cassandraId)
-                            .map(aclWithVersion ->
-                                updateStoredACL(cassandraId, aclTransformation.apply(aclWithVersion))
-                                    .map(newACL -> ACLDiff.computeDiff(aclWithVersion.mailboxACL, newACL)))
-                            .orElseGet(() -> insertACL(cassandraId, replacement)
-                                .map(newACL -> ACLDiff.computeDiff(MailboxACL.EMPTY, newACL)));
-                    });
-        } catch (LightweightTransactionException e) {
-            throw new MailboxException("Exception during lightweight transaction", e);
-        }
-    }
-
-    private CompletableFuture<ResultSet> getStoredACLRow(CassandraId cassandraId) {
-        return executor.execute(
+        return updateAcl(cassandraId, acl -> new ACLWithVersion(acl.version, mailboxACL), mailboxACL)
+            .flatMap(aclDiff -> userMailboxRightsDAO.update(cassandraId, aclDiff)
+            .thenReturn(aclDiff))
+            .blockOptional()
+            .orElseThrow(() -> new MailboxException("Unable to update ACL"));
+    }
+
+    private Mono<ACLDiff> updateAcl(CassandraId cassandraId, Function<ACLWithVersion, ACLWithVersion> aclTransformation, MailboxACL replacement) throws MailboxException {
+        return Mono.fromRunnable(() -> codeInjector.inject())
+            .then(Mono.defer(() -> getAclWithVersion(cassandraId)))
+            .flatMap(aclWithVersion ->
+                    updateStoredACL(cassandraId, aclTransformation.apply(aclWithVersion))
+                            .map(newACL -> ACLDiff.computeDiff(aclWithVersion.mailboxACL, newACL)))
+            .switchIfEmpty(insertACL(cassandraId, replacement)
+                    .map(newACL -> ACLDiff.computeDiff(MailboxACL.EMPTY, newACL)))
+            .single()
+            .retry(maxAclRetry);
+    }
+
+    private Mono<Row> getStoredACLRow(CassandraId cassandraId) {
+        return executor.executeSingleRowReactor(
             readStatement.bind()
                 .setUUID(CassandraACLTable.ID, cassandraId.asUuid()));
     }
 
-    private Optional<MailboxACL> updateStoredACL(CassandraId cassandraId, ACLWithVersion aclWithVersion) {
-        try {
-            return executor.executeReturnApplied(
-                conditionalUpdateStatement.bind()
+    private Mono<MailboxACL> updateStoredACL(CassandraId cassandraId, ACLWithVersion aclWithVersion) {
+        return executor.executeReturnApplied(
+            conditionalUpdateStatement.bind()
+                .setUUID(CassandraACLTable.ID, cassandraId.asUuid())
+                .setString(CassandraACLTable.ACL, convertAclToJson(aclWithVersion.mailboxACL))
+                .setLong(CassandraACLTable.VERSION, aclWithVersion.version + 1)
+                .setLong(OLD_VERSION, aclWithVersion.version))
+            .filter(FunctionalUtils.toPredicate(Function.identity()))
+            .map(any -> aclWithVersion.mailboxACL);
+    }
+
+    private Mono<MailboxACL> insertACL(CassandraId cassandraId, MailboxACL acl) {
+        return Mono.defer(() -> executor.executeReturnApplied(
+            conditionalInsertStatement.bind()
                     .setUUID(CassandraACLTable.ID, cassandraId.asUuid())
-                    .setString(CassandraACLTable.ACL,  MailboxACLJsonConverter.toJson(aclWithVersion.mailboxACL))
-                    .setLong(CassandraACLTable.VERSION, aclWithVersion.version + 1)
-                    .setLong(OLD_VERSION, aclWithVersion.version))
-                .thenApply(Optional::of)
-                .thenApply(optional -> optional.filter(b -> b).map(any -> aclWithVersion.mailboxACL))
-                .join();
-        } catch (JsonProcessingException exception) {
-            throw new RuntimeException(exception);
-        }
+                    .setString(CassandraACLTable.ACL, convertAclToJson(acl))))
+            .filter(FunctionalUtils.toPredicate(Function.identity()))
+            .map(any -> acl);
     }
 
-    private Optional<MailboxACL> insertACL(CassandraId cassandraId, MailboxACL acl) {
+    private String convertAclToJson(MailboxACL acl) {
         try {
-            return executor.executeReturnApplied(
-                conditionalInsertStatement.bind()
-                    .setUUID(CassandraACLTable.ID, cassandraId.asUuid())
-                    .setString(CassandraACLTable.ACL, MailboxACLJsonConverter.toJson(acl)))
-                .thenApply(Optional::of)
-                .thenApply(optional -> optional.filter(b -> b).map(any -> acl))
-                .join();
+            return MailboxACLJsonConverter.toJson(acl);
         } catch (JsonProcessingException exception) {
             throw new RuntimeException(exception);
         }
     }
 
-    private Optional<ACLWithVersion> getAclWithVersion(CassandraId cassandraId) {
-        ResultSet resultSet = getStoredACLRow(cassandraId).join();
-        if (resultSet.isExhausted()) {
-            return Optional.empty();
-        }
-        Row row = resultSet.one();
-        return Optional.of(
-            new ACLWithVersion(
-                row.getLong(CassandraACLTable.VERSION),
-                deserializeACL(cassandraId, row.getString(CassandraACLTable.ACL))));
+    private Mono<ACLWithVersion> getAclWithVersion(CassandraId cassandraId) {
+        return getStoredACLRow(cassandraId)
+            .map(acl -> new ACLWithVersion(acl.getLong(CassandraACLTable.VERSION),
+                                deserializeACL(cassandraId, acl.getString(CassandraACLTable.ACL))));
     }
 
     private MailboxACL deserializeACL(CassandraId cassandraId, String serializedACL) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java
index 2e5c767..fb00ec0 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAO.java
@@ -33,7 +33,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentTable.
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.stream.Stream;
 
@@ -49,6 +48,7 @@ import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.google.common.base.Preconditions;
+import reactor.core.publisher.Mono;
 
 public class CassandraAttachmentDAO {
 
@@ -99,12 +99,12 @@ public class CassandraAttachmentDAO {
             .from(TABLE_NAME));
     }
 
-    public CompletableFuture<Optional<Attachment>> getAttachment(AttachmentId attachmentId) {
+    public Mono<Attachment> getAttachment(AttachmentId attachmentId) {
         Preconditions.checkArgument(attachmentId != null);
-        return cassandraAsyncExecutor.executeSingleRow(
+        return cassandraAsyncExecutor.executeSingleRowReactor(
             selectStatement.bind()
                 .setString(ID, attachmentId.getId()))
-            .thenApply(optional -> optional.map(this::attachment));
+            .map(this::attachment);
     }
 
     public Stream<Attachment> retrieveAll() {

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2.java
----------------------------------------------------------------------
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 f88723f..38b6e21 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
@@ -32,8 +32,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentV2Tabl
 import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentV2Table.TYPE;
 
 import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
@@ -46,6 +44,7 @@ import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.google.common.base.Preconditions;
+import reactor.core.publisher.Mono;
 
 public class CassandraAttachmentDAOV2 {
     public static class DAOAttachment {
@@ -150,16 +149,16 @@ public class CassandraAttachmentDAOV2 {
             .where(eq(ID_AS_UUID, bindMarker(ID_AS_UUID))));
     }
 
-    public CompletableFuture<Optional<DAOAttachment>> getAttachment(AttachmentId attachmentId) {
+    public Mono<DAOAttachment> getAttachment(AttachmentId attachmentId) {
         Preconditions.checkArgument(attachmentId != null);
-        return cassandraAsyncExecutor.executeSingleRow(
+        return cassandraAsyncExecutor.executeSingleRowReactor(
             selectStatement.bind()
                 .setUUID(ID_AS_UUID, attachmentId.asUUID()))
-            .thenApply(rowOptional -> rowOptional.map(row -> CassandraAttachmentDAOV2.fromRow(row, blobIdFactory)));
+            .map(row -> CassandraAttachmentDAOV2.fromRow(row, blobIdFactory));
     }
 
-    public CompletableFuture<Void> storeAttachment(DAOAttachment attachment) {
-        return cassandraAsyncExecutor.executeVoid(
+    public Mono<Void> storeAttachment(DAOAttachment attachment) {
+        return cassandraAsyncExecutor.executeVoidReactor(
             insertStatement.bind()
                 .setUUID(ID_AS_UUID, attachment.getAttachmentId().asUUID())
                 .setString(ID, attachment.getAttachmentId().getId())

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java
index ecb43de..a7d9dfc 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java
@@ -21,10 +21,6 @@ package org.apache.james.mailbox.cassandra.mail;
 
 import java.util.Collection;
 import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-import java.util.stream.Stream;
 
 import javax.inject.Inject;
 
@@ -37,13 +33,14 @@ import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.store.mail.AttachmentMapper;
 import org.apache.james.mailbox.store.mail.model.Username;
-import org.apache.james.util.FluentFutureStream;
+import org.apache.james.util.ReactorUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraAttachmentMapper implements AttachmentMapper {
     private static final Logger LOGGER = LoggerFactory.getLogger(CassandraAttachmentMapper.class);
@@ -76,65 +73,54 @@ public class CassandraAttachmentMapper implements AttachmentMapper {
     public Attachment getAttachment(AttachmentId attachmentId) throws AttachmentNotFoundException {
         Preconditions.checkArgument(attachmentId != null);
         return getAttachmentInternal(attachmentId)
-            .join()
+            .blockOptional()
             .orElseThrow(() -> new AttachmentNotFoundException(attachmentId.getId()));
     }
 
-    private CompletionStage<Optional<Attachment>> retrievePayload(Optional<DAOAttachment> daoAttachmentOptional) {
-        if (!daoAttachmentOptional.isPresent()) {
-            return CompletableFuture.completedFuture(Optional.empty());
-        }
-        DAOAttachment daoAttachment = daoAttachmentOptional.get();
-        return blobStore.readBytes(daoAttachment.getBlobId())
-            .thenApply(bytes -> Optional.of(daoAttachment.toAttachment(bytes)));
+    private Mono<Attachment> retrievePayload(DAOAttachment daoAttachment) {
+        return Mono.fromCompletionStage(blobStore.readBytes(daoAttachment.getBlobId())
+            .thenApply(daoAttachment::toAttachment));
     }
 
     @Override
     public List<Attachment> getAttachments(Collection<AttachmentId> attachmentIds) {
-        return getAttachmentsAsFuture(attachmentIds).join();
-    }
-
-    public CompletableFuture<ImmutableList<Attachment>> getAttachmentsAsFuture(Collection<AttachmentId> attachmentIds) {
         Preconditions.checkArgument(attachmentIds != null);
+        return Flux.fromIterable(attachmentIds)
+            .flatMap(this::getAttachmentsAsMono)
+            .collectList()
+            .block();
+    }
 
-        Stream<CompletableFuture<Optional<Attachment>>> attachments = attachmentIds
-                .stream()
-                .distinct()
-                .map(id -> getAttachmentInternal(id)
-                    .thenApply(finalValue -> logNotFound(id, finalValue)));
-
-        return FluentFutureStream.of(attachments, FluentFutureStream::unboxOptional)
-            .collect(Guavate.toImmutableList());
+    public Mono<Attachment> getAttachmentsAsMono(AttachmentId attachmentId) {
+        return getAttachmentInternal(attachmentId)
+            .switchIfEmpty(ReactorUtils.executeAndEmpty(() -> logNotFound((attachmentId))));
     }
 
-    private CompletableFuture<Optional<Attachment>> getAttachmentInternal(AttachmentId id) {
+    private Mono<Attachment> getAttachmentInternal(AttachmentId id) {
         return attachmentDAOV2.getAttachment(id)
-            .thenCompose(this::retrievePayload)
-            .thenCompose(v2Value -> fallbackToV1(id, v2Value));
+            .flatMap(this::retrievePayload)
+            .switchIfEmpty(fallbackToV1(id));
     }
 
-    private CompletionStage<Optional<Attachment>> fallbackToV1(AttachmentId attachmentId, Optional<Attachment> v2Value) {
-        if (v2Value.isPresent()) {
-            return CompletableFuture.completedFuture(v2Value);
-        }
+    private Mono<Attachment> fallbackToV1(AttachmentId attachmentId) {
         return attachmentDAO.getAttachment(attachmentId);
     }
 
     @Override
     public void storeAttachmentForOwner(Attachment attachment, Username owner) throws MailboxException {
         ownerDAO.addOwner(attachment.getAttachmentId(), owner)
-            .thenCompose(any -> blobStore.save(attachment.getBytes()))
-            .thenApply(blobId -> CassandraAttachmentDAOV2.from(attachment, blobId))
-            .thenCompose(attachmentDAOV2::storeAttachment)
-            .join();
+            .then(Mono.fromFuture(blobStore.save(attachment.getBytes())))
+            .map(blobId -> CassandraAttachmentDAOV2.from(attachment, blobId))
+            .flatMap(attachmentDAOV2::storeAttachment)
+            .block();
     }
 
     @Override
     public void storeAttachmentsForMessage(Collection<Attachment> attachments, MessageId ownerMessageId) throws MailboxException {
-        FluentFutureStream.of(
-            attachments.stream()
-                .map(attachment -> storeAttachmentAsync(attachment, ownerMessageId)))
-            .join();
+        Flux.fromIterable(attachments)
+            .flatMap(attachment -> storeAttachmentAsync(attachment, ownerMessageId))
+            .then()
+            .block();
     }
 
     @Override
@@ -148,21 +134,18 @@ public class CassandraAttachmentMapper implements AttachmentMapper {
         return ownerDAO.retrieveOwners(attachmentId).join().collect(Guavate.toImmutableList());
     }
 
-    public CompletableFuture<Void> storeAttachmentAsync(Attachment attachment, MessageId ownerMessageId) {
-        return blobStore.save(attachment.getBytes())
-            .thenApply(blobId -> CassandraAttachmentDAOV2.from(attachment, blobId))
-            .thenCompose(daoAttachment -> storeAttachmentWithIndex(daoAttachment, ownerMessageId));
+    public Mono<Void> storeAttachmentAsync(Attachment attachment, MessageId ownerMessageId) {
+        return Mono.fromFuture(blobStore.save(attachment.getBytes())
+            .thenApply(blobId -> CassandraAttachmentDAOV2.from(attachment, blobId)))
+            .flatMap(daoAttachment -> storeAttachmentWithIndex(daoAttachment, ownerMessageId));
     }
 
-    private CompletableFuture<Void> storeAttachmentWithIndex(DAOAttachment daoAttachment, MessageId ownerMessageId) {
+    private Mono<Void> storeAttachmentWithIndex(DAOAttachment daoAttachment, MessageId ownerMessageId) {
         return attachmentDAOV2.storeAttachment(daoAttachment)
-                .thenCompose(any -> attachmentMessageIdDAO.storeAttachmentForMessageId(daoAttachment.getAttachmentId(), ownerMessageId));
+                .then(attachmentMessageIdDAO.storeAttachmentForMessageId(daoAttachment.getAttachmentId(), ownerMessageId));
     }
 
-    private Optional<Attachment> logNotFound(AttachmentId attachmentId, Optional<Attachment> optionalAttachment) {
-        if (!optionalAttachment.isPresent()) {
-            LOGGER.warn("Failed retrieving attachment {}", attachmentId);
-        }
-        return optionalAttachment;
+    private void logNotFound(AttachmentId attachmentId) {
+        LOGGER.warn("Failed retrieving attachment {}", attachmentId);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java
----------------------------------------------------------------------
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 88b3d4d..3f02c1a 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
@@ -44,6 +44,7 @@ import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Preconditions;
+import reactor.core.publisher.Mono;
 
 public class CassandraAttachmentMessageIdDAO {
 
@@ -91,8 +92,8 @@ public class CassandraAttachmentMessageIdDAO {
         return messageIdFactory.fromString(row.getString(MESSAGE_ID));
     }
 
-    public CompletableFuture<Void> storeAttachmentForMessageId(AttachmentId attachmentId, MessageId ownerMessageId) {
-        return cassandraAsyncExecutor.executeVoid(
+    public Mono<Void> storeAttachmentForMessageId(AttachmentId attachmentId, MessageId ownerMessageId) {
+        return cassandraAsyncExecutor.executeVoidReactor(
             insertStatement.bind()
                 .setUUID(ATTACHMENT_ID_AS_UUID, attachmentId.asUUID())
                 .setString(ATTACHMENT_ID, attachmentId.getId())

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java
index e92757c..fce332d 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAO.java
@@ -41,6 +41,7 @@ import org.apache.james.mailbox.store.mail.model.Username;
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
+import reactor.core.publisher.Mono;
 
 public class CassandraAttachmentOwnerDAO {
 
@@ -72,8 +73,8 @@ public class CassandraAttachmentOwnerDAO {
                 .where(eq(ID, bindMarker(ID))));
     }
 
-    public CompletableFuture<Void> addOwner(AttachmentId attachmentId, Username owner) {
-        return executor.executeVoid(
+    public Mono<Void> addOwner(AttachmentId attachmentId, Username owner) {
+        return executor.executeVoidReactor(
             addStatement.bind()
                 .setUUID(ID, attachmentId.asUUID())
                 .setString(OWNER, owner.getValue()));

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java
index 96075a4..7e75099 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAO.java
@@ -32,7 +32,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.NAM
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.TABLE_NAME;
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.UIDVALIDITY;
 
-import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
@@ -46,13 +45,14 @@ import org.apache.james.mailbox.cassandra.table.CassandraMailboxTable;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.store.mail.model.Mailbox;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
-import org.apache.james.util.FluentFutureStream;
 
 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.annotations.VisibleForTesting;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraMailboxDAO {
 
@@ -112,9 +112,9 @@ public class CassandraMailboxDAO {
             .where(eq(ID, bindMarker(ID))));
     }
 
-    public CompletableFuture<Void> save(Mailbox mailbox) {
+    public Mono<Void> save(Mailbox mailbox) {
         CassandraId cassandraId = (CassandraId) mailbox.getMailboxId();
-        return executor.executeVoid(insertStatement.bind()
+        return executor.executeVoidReactor(insertStatement.bind()
             .setUUID(ID, cassandraId.asUuid())
             .setString(NAME, mailbox.getName())
             .setLong(UIDVALIDITY, mailbox.getUidValidity())
@@ -128,21 +128,21 @@ public class CassandraMailboxDAO {
             .setUDTValue(MAILBOX_BASE, mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), mailboxPath.getUser())));
     }
 
-    public CompletableFuture<Void> delete(CassandraId mailboxId) {
-        return executor.executeVoid(deleteStatement.bind()
+    public Mono<Void> delete(CassandraId mailboxId) {
+        return executor.executeVoidReactor(deleteStatement.bind()
             .setUUID(ID, mailboxId.asUuid()));
     }
 
-    public CompletableFuture<Optional<SimpleMailbox>> retrieveMailbox(CassandraId mailboxId) {
-        return executor.executeSingleRow(readStatement.bind()
+    public Mono<SimpleMailbox> retrieveMailbox(CassandraId mailboxId) {
+        return executor.executeSingleRowReactor(readStatement.bind()
             .setUUID(ID, mailboxId.asUuid()))
-            .thenApply(rowOptional -> rowOptional.map(this::mailboxFromRow))
-            .thenApply(mailbox -> addMailboxId(mailboxId, mailbox));
+            .map(this::mailboxFromRow)
+            .map(mailbox -> addMailboxId(mailboxId, mailbox));
     }
 
-    private Optional<SimpleMailbox> addMailboxId(CassandraId cassandraId, Optional<SimpleMailbox> mailboxOptional) {
-        mailboxOptional.ifPresent(mailbox -> mailbox.setMailboxId(cassandraId));
-        return mailboxOptional;
+    private SimpleMailbox addMailboxId(CassandraId cassandraId, SimpleMailbox mailbox) {
+        mailbox.setMailboxId(cassandraId);
+        return mailbox;
     }
 
     private SimpleMailbox mailboxFromRow(Row row) {
@@ -154,9 +154,9 @@ public class CassandraMailboxDAO {
             row.getLong(UIDVALIDITY));
     }
 
-    public FluentFutureStream<SimpleMailbox> retrieveAllMailboxes() {
-        return FluentFutureStream.of(executor.execute(listStatement.bind())
-            .thenApply(cassandraUtils::convertToStream))
+    public Flux<SimpleMailbox> retrieveAllMailboxes() {
+        return executor.executeReactor(listStatement.bind())
+            .flatMapMany(cassandraUtils::convertToFlux)
             .map(this::toMailboxWithId);
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
----------------------------------------------------------------------
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 4d3b7fd..058d6fe 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
@@ -21,18 +21,14 @@ package org.apache.james.mailbox.cassandra.mail;
 
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 import java.util.StringTokenizer;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-import java.util.function.Function;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 import javax.inject.Inject;
 
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.mailbox.acl.ACLDiff;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.exception.MailboxException;
@@ -45,20 +41,19 @@ import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.store.mail.MailboxMapper;
 import org.apache.james.mailbox.store.mail.model.Mailbox;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
-import org.apache.james.util.CompletableFutureUtil;
-import org.apache.james.util.FluentFutureStream;
-import org.apache.james.util.OptionalUtils;
+import org.apache.james.util.ReactorUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.github.fge.lambdas.Throwing;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraMailboxMapper implements MailboxMapper {
 
-    public static final String WILDCARD = "%";
+    private static final String WILDCARD = "%";
     public static final Logger LOGGER = LoggerFactory.getLogger(CassandraMailboxMapper.class);
 
     private final CassandraMailboxDAO mailboxDAO;
@@ -79,77 +74,70 @@ public class CassandraMailboxMapper implements MailboxMapper {
     @Override
     public void delete(Mailbox mailbox) {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
-        FluentFutureStream.ofFutures(
+        Flux.merge(
                 mailboxPathDAO.delete(mailbox.generateAssociatedPath()),
                 mailboxPathV2DAO.delete(mailbox.generateAssociatedPath()))
-            .map(any -> mailboxDAO.delete(mailboxId), FluentFutureStream::unboxFuture)
-            .join();
+            .thenEmpty(mailboxDAO.delete(mailboxId))
+            .block();
     }
 
     @Override
     public Mailbox findMailboxByPath(MailboxPath path) throws MailboxException {
         return mailboxPathV2DAO.retrieveId(path)
-            .thenCompose(cassandraIdOptional ->
-                cassandraIdOptional
-                    .map(CassandraIdAndPath::getCassandraId)
-                    .map(this::retrieveMailbox)
-                    .orElseGet(Throwing.supplier(() -> fromPreviousTable(path))))
-            .join()
+            .map(CassandraIdAndPath::getCassandraId)
+            .flatMap(this::retrieveMailbox)
+            .switchIfEmpty(fromPreviousTable(path))
+            .blockOptional()
             .orElseThrow(() -> new MailboxNotFoundException(path));
     }
 
-    private CompletableFuture<Optional<SimpleMailbox>> fromPreviousTable(MailboxPath path) {
+    private Mono<SimpleMailbox> fromPreviousTable(MailboxPath path) {
         return mailboxPathDAO.retrieveId(path)
-            .thenCompose(cassandraIdOptional ->
-                cassandraIdOptional
-                    .map(CassandraIdAndPath::getCassandraId)
-                    .map(this::retrieveMailbox)
-                    .orElse(CompletableFuture.completedFuture(Optional.empty())))
-            .thenCompose(maybeMailbox -> maybeMailbox.map(this::migrate)
-                .orElse(CompletableFuture.completedFuture(maybeMailbox)));
+            .map(CassandraIdAndPath::getCassandraId)
+            .flatMap(this::retrieveMailbox)
+            .flatMap(this::migrate);
     }
 
-    private CompletableFuture<Optional<SimpleMailbox>> migrate(SimpleMailbox mailbox) {
+    private Mono<SimpleMailbox> migrate(SimpleMailbox mailbox) {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
         return mailboxPathV2DAO.save(mailbox.generateAssociatedPath(), mailboxId)
-            .thenCompose(success -> deleteIfSuccess(mailbox, success))
-            .thenApply(any -> Optional.of(mailbox));
+            .flatMap(success -> deleteIfSuccess(mailbox, success))
+            .thenReturn(mailbox);
     }
 
-    private CompletionStage<Void> deleteIfSuccess(SimpleMailbox mailbox, boolean success) {
+    private Mono<Void> deleteIfSuccess(SimpleMailbox mailbox, boolean success) {
         if (success) {
             return mailboxPathDAO.delete(mailbox.generateAssociatedPath());
         }
         LOGGER.info("Concurrent execution lead to data race while migrating {} to 'mailboxPathV2DAO'.",
             mailbox.generateAssociatedPath());
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
     @Override
     public Mailbox findMailboxById(MailboxId id) throws MailboxException {
         CassandraId mailboxId = (CassandraId) id;
         return retrieveMailbox(mailboxId)
-            .join()
+            .blockOptional()
             .orElseThrow(() -> new MailboxNotFoundException(id));
     }
 
-    private CompletableFuture<Optional<SimpleMailbox>> retrieveMailbox(CassandraId mailboxId) {
-        CompletableFuture<MailboxACL> aclCompletableFuture = cassandraACLMapper.getACL(mailboxId);
+    private Mono<SimpleMailbox> retrieveMailbox(CassandraId mailboxId) {
+        Mono<MailboxACL> aclCompletableFuture = cassandraACLMapper.getACL(mailboxId);
+        Mono<SimpleMailbox> simpleMailboxFuture = mailboxDAO.retrieveMailbox(mailboxId);
 
-        CompletableFuture<Optional<SimpleMailbox>> simpleMailboxFuture = mailboxDAO.retrieveMailbox(mailboxId);
-
-        return aclCompletableFuture.thenCombine(simpleMailboxFuture, this::addAcl);
+        return aclCompletableFuture.zipWith(simpleMailboxFuture, this::addAcl);
     }
 
-    private Optional<SimpleMailbox> addAcl(MailboxACL acl, Optional<SimpleMailbox> mailboxOptional) {
-        mailboxOptional.ifPresent(mailbox -> mailbox.setACL(acl));
-        return mailboxOptional;
+    private SimpleMailbox addAcl(MailboxACL acl, SimpleMailbox mailbox) {
+        mailbox.setACL(acl);
+        return mailbox;
     }
 
     @Override
     public List<Mailbox> findMailboxWithPathLike(MailboxPath path) {
-        List<Mailbox> mailboxesV2 = toMailboxes(path, mailboxPathV2DAO.listUserMailboxes(path.getNamespace(), path.getUser()));
-        List<Mailbox> mailboxesV1 = toMailboxes(path, mailboxPathDAO.listUserMailboxes(path.getNamespace(), path.getUser()));
+        List<SimpleMailbox> mailboxesV2 = toMailboxes(path, mailboxPathV2DAO.listUserMailboxes(path.getNamespace(), path.getUser()));
+        List<SimpleMailbox> mailboxesV1 = toMailboxes(path, mailboxPathDAO.listUserMailboxes(path.getNamespace(), path.getUser()));
 
         List<Mailbox> mailboxesV1NotInV2 = mailboxesV1.stream()
             .filter(mailboxV1 -> mailboxesV2.stream()
@@ -163,19 +151,19 @@ public class CassandraMailboxMapper implements MailboxMapper {
             .build();
     }
 
-    private List<Mailbox> toMailboxes(MailboxPath path, CompletableFuture<Stream<CassandraIdAndPath>> listUserMailboxes) {
+    private List<SimpleMailbox> toMailboxes(MailboxPath path, Flux<CassandraIdAndPath> listUserMailboxes) {
         Pattern regex = Pattern.compile(constructEscapedRegexForMailboxNameMatching(path));
 
-        return FluentFutureStream.of(listUserMailboxes)
+        return listUserMailboxes
                 .filter(idAndPath -> regex.matcher(idAndPath.getMailboxPath().getName()).matches())
-                .map(this::retrieveMailbox, FluentFutureStream::unboxFutureOptional)
-                .join()
-                .collect(Guavate.toImmutableList());
+                .flatMap(this::retrieveMailbox)
+                .collectList()
+                .block();
     }
 
-    private CompletableFuture<Optional<SimpleMailbox>> retrieveMailbox(CassandraIdAndPath idAndPath) {
+    private Mono<SimpleMailbox> retrieveMailbox(CassandraIdAndPath idAndPath) {
         return retrieveMailbox(idAndPath.getCassandraId())
-            .thenApply(optional -> OptionalUtils.executeIfEmpty(optional,
+            .switchIfEmpty(ReactorUtils.executeAndEmpty(
                 () -> LOGGER.warn("Could not retrieve mailbox {} with path {} in mailbox table.", idAndPath.getCassandraId(), idAndPath.getMailboxPath())));
     }
 
@@ -186,22 +174,20 @@ public class CassandraMailboxMapper implements MailboxMapper {
 
         CassandraId cassandraId = retrieveId(cassandraMailbox);
         cassandraMailbox.setMailboxId(cassandraId);
-        boolean applied = trySave(cassandraMailbox, cassandraId).join();
-        if (!applied) {
+        if (!trySave(cassandraMailbox, cassandraId)) {
             throw new MailboxExistsException(mailbox.generateAssociatedPath().asString());
         }
         return cassandraId;
     }
 
-    private CompletableFuture<Boolean> trySave(SimpleMailbox cassandraMailbox, CassandraId cassandraId) {
-        return mailboxPathV2DAO.save(cassandraMailbox.generateAssociatedPath(), cassandraId)
-            .thenCompose(CompletableFutureUtil.composeIfTrue(
-                () -> retrieveMailbox(cassandraId)
-                    .thenCompose(optional -> CompletableFuture
-                        .allOf(optional
-                                .map(storedMailbox -> mailboxPathV2DAO.delete(storedMailbox.generateAssociatedPath()))
-                                .orElse(CompletableFuture.completedFuture(null)),
-                            mailboxDAO.save(cassandraMailbox)))));
+    private boolean trySave(SimpleMailbox cassandraMailbox, CassandraId cassandraId) {
+        boolean isCreated = mailboxPathV2DAO.save(cassandraMailbox.generateAssociatedPath(), cassandraId).block();
+        if (isCreated) {
+            Optional<SimpleMailbox> simpleMailbox = retrieveMailbox(cassandraId).blockOptional();
+            simpleMailbox.ifPresent(mbx -> mailboxPathV2DAO.delete(mbx.generateAssociatedPath()).block());
+            mailboxDAO.save(cassandraMailbox).block();
+        }
+        return isCreated;
     }
 
     private CassandraId retrieveId(SimpleMailbox cassandraMailbox) {
@@ -214,21 +200,21 @@ public class CassandraMailboxMapper implements MailboxMapper {
 
     @Override
     public boolean hasChildren(Mailbox mailbox, char delimiter) {
-        return ImmutableList.of(
+        return Flux.merge(
                 mailboxPathDAO.listUserMailboxes(mailbox.getNamespace(), mailbox.getUser()),
                 mailboxPathV2DAO.listUserMailboxes(mailbox.getNamespace(), mailbox.getUser()))
-            .stream()
-            .map(CompletableFuture::join)
-            .flatMap(Function.identity())
-            .anyMatch(idAndPath -> idAndPath.getMailboxPath().getName().startsWith(mailbox.getName() + String.valueOf(delimiter)));
+            .filter(idAndPath -> idAndPath.getMailboxPath().getName().startsWith(mailbox.getName() + String.valueOf(delimiter)))
+            .hasElements()
+            .block();
     }
 
     @Override
     public List<Mailbox> list() {
         return mailboxDAO.retrieveAllMailboxes()
-            .map(this::toMailboxWithAclFuture, FluentFutureStream::unboxFuture)
-            .join()
-            .collect(Guavate.toImmutableList());
+            .flatMap(this::toMailboxWithAcl)
+            .map(simpleMailboxes -> (Mailbox) simpleMailboxes)
+            .collectList()
+            .block();
     }
 
     @Override
@@ -269,10 +255,10 @@ public class CassandraMailboxMapper implements MailboxMapper {
         }
     }
 
-    private CompletableFuture<SimpleMailbox> toMailboxWithAclFuture(SimpleMailbox mailbox) {
+    private Mono<SimpleMailbox> toMailboxWithAcl(SimpleMailbox mailbox) {
         CassandraId cassandraId = (CassandraId) mailbox.getMailboxId();
         return cassandraACLMapper.getACL(cassandraId)
-            .thenApply(acl -> {
+            .map(acl -> {
                 mailbox.setACL(acl);
                 return mailbox;
             });
@@ -280,18 +266,17 @@ public class CassandraMailboxMapper implements MailboxMapper {
 
     @Override
     public List<Mailbox> findNonPersonalMailboxes(String userName, Right right) {
-        return FluentFutureStream.of(userMailboxRightsDAO.listRightsForUser(userName)
-            .thenApply(map -> toAuthorizedMailboxIds(map, right)))
-            .map(this::retrieveMailbox, FluentFutureStream::unboxFutureOptional)
-            .join()
-            .collect(Guavate.toImmutableList());
+        return userMailboxRightsDAO.listRightsForUser(userName)
+            .filter(mailboxId -> authorizedMailbox(mailboxId.getRight(), right))
+            .map(Pair::getLeft)
+            .flatMap(this::retrieveMailbox)
+            .map(simpleMailboxes -> (Mailbox) simpleMailboxes)
+            .collectList()
+            .block();
     }
 
-    private Stream<CassandraId> toAuthorizedMailboxIds(Map<CassandraId, MailboxACL.Rfc4314Rights> map, Right right) {
-        return map.entrySet()
-            .stream()
-            .filter(Throwing.predicate(entry -> entry.getValue().contains(right)))
-            .map(Map.Entry::getKey);
+    private boolean authorizedMailbox(MailboxACL.Rfc4314Rights rights, Right right) {
+        return rights.contains(right);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAO.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAO.java
index 33fac3c..1eee863 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAO.java
@@ -19,23 +19,24 @@
 
 package org.apache.james.mailbox.cassandra.mail;
 
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
-
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.model.MailboxPath;
 
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
 public interface CassandraMailboxPathDAO {
 
-    CompletableFuture<Optional<CassandraIdAndPath>> retrieveId(MailboxPath mailboxPath);
+    Mono<CassandraIdAndPath> retrieveId(MailboxPath mailboxPath);
+
+    Flux<CassandraIdAndPath> listUserMailboxes(String namespace, String user);
 
-    CompletableFuture<Stream<CassandraIdAndPath>> listUserMailboxes(String namespace, String user);
+    void logGhostMailboxSuccess(CassandraIdAndPath value);
 
-    Optional<CassandraIdAndPath> logGhostMailbox(MailboxPath mailboxPath, Optional<CassandraIdAndPath> value);
+    void logGhostMailboxFailure(MailboxPath mailboxPath);
 
-    CompletableFuture<Boolean> save(MailboxPath mailboxPath, CassandraId mailboxId);
+    Mono<Boolean> save(MailboxPath mailboxPath, CassandraId mailboxId);
 
-    CompletableFuture<Void> delete(MailboxPath mailboxPath);
+    Mono<Void> delete(MailboxPath mailboxPath);
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java
index 41f5dd0..46975a0 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImpl.java
@@ -31,7 +31,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable.NAMESPACE_AND_USER;
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable.TABLE_NAME;
 
-import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.stream.Stream;
 
@@ -45,12 +44,16 @@ import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.mail.utils.MailboxBaseTupleUtil;
 import org.apache.james.mailbox.cassandra.table.CassandraMailboxTable;
 import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.util.FunctionalUtils;
+import org.apache.james.util.ReactorUtils;
 
 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.annotations.VisibleForTesting;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraMailboxPathDAOImpl implements CassandraMailboxPathDAO {
 
@@ -80,7 +83,7 @@ public class CassandraMailboxPathDAOImpl implements CassandraMailboxPathDAO {
     }
 
     @VisibleForTesting
-    public CassandraMailboxPathDAOImpl(Session session, CassandraTypesProvider typesProvider) {
+     CassandraMailboxPathDAOImpl(Session session, CassandraTypesProvider typesProvider) {
         this(session, typesProvider, CassandraUtils.WITH_DEFAULT_CONFIGURATION);
     }
 
@@ -122,24 +125,24 @@ public class CassandraMailboxPathDAOImpl implements CassandraMailboxPathDAO {
             .from(TABLE_NAME));
     }
 
-    public CompletableFuture<Optional<CassandraIdAndPath>> retrieveId(MailboxPath mailboxPath) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    public Mono<CassandraIdAndPath> retrieveId(MailboxPath mailboxPath) {
+        return cassandraAsyncExecutor.executeSingleRowReactor(
             select.bind()
                 .setUDTValue(NAMESPACE_AND_USER, mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), mailboxPath.getUser()))
                 .setString(MAILBOX_NAME, mailboxPath.getName()))
-            .thenApply(rowOptional ->
-                rowOptional.map(this::fromRowToCassandraIdAndPath))
-            .thenApply(value -> logGhostMailbox(mailboxPath, value));
+            .map(this::fromRowToCassandraIdAndPath)
+            .map(FunctionalUtils.toFunction(this::logGhostMailboxSuccess))
+            .switchIfEmpty(ReactorUtils.executeAndEmpty(() -> logGhostMailboxFailure(mailboxPath)));
     }
 
     @Override
-    public CompletableFuture<Stream<CassandraIdAndPath>> listUserMailboxes(String namespace, String user) {
-        return cassandraAsyncExecutor.execute(
+    public Flux<CassandraIdAndPath> listUserMailboxes(String namespace, String user) {
+        return cassandraAsyncExecutor.executeReactor(
             selectAllForUser.bind()
                 .setUDTValue(NAMESPACE_AND_USER, mailboxBaseTupleUtil.createMailboxBaseUDT(namespace, user)))
-            .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet)
+            .flatMapMany(resultSet -> cassandraUtils.convertToFlux(resultSet)
                 .map(this::fromRowToCassandraIdAndPath)
-                .peek(this::logReadSuccess));
+                .map(FunctionalUtils.toFunction(this::logReadSuccess)));
     }
 
     /**
@@ -149,19 +152,19 @@ public class CassandraMailboxPathDAOImpl implements CassandraMailboxPathDAO {
      * reads and write operations are also added in order to allow audit in order to know if the mailbox existed.
      */
     @Override
-    public Optional<CassandraIdAndPath> logGhostMailbox(MailboxPath mailboxPath, Optional<CassandraIdAndPath> value) {
-        if (value.isPresent()) {
-            CassandraIdAndPath cassandraIdAndPath = value.get();
-            logReadSuccess(cassandraIdAndPath);
-        } else {
-            GhostMailbox.logger()
+    public void logGhostMailboxSuccess(CassandraIdAndPath value) {
+        logReadSuccess(value);
+    }
+
+    @Override
+    public void logGhostMailboxFailure(MailboxPath mailboxPath) {
+        GhostMailbox.logger()
                 .addField(GhostMailbox.MAILBOX_NAME, mailboxPath)
                 .addField(TYPE, "readMiss")
                 .log(logger -> logger.info("Read mailbox missed"));
-        }
-        return value;
     }
 
+
     /**
      * See https://issues.apache.org/jira/browse/MAILBOX-322 to read about the Ghost mailbox bug.
      *
@@ -185,7 +188,7 @@ public class CassandraMailboxPathDAOImpl implements CassandraMailboxPathDAO {
     }
 
     @Override
-    public CompletableFuture<Boolean> save(MailboxPath mailboxPath, CassandraId mailboxId) {
+    public Mono<Boolean> save(MailboxPath mailboxPath, CassandraId mailboxId) {
         return cassandraAsyncExecutor.executeReturnApplied(insert.bind()
             .setUDTValue(NAMESPACE_AND_USER, mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), mailboxPath.getUser()))
             .setString(MAILBOX_NAME, mailboxPath.getName())
@@ -193,8 +196,8 @@ public class CassandraMailboxPathDAOImpl implements CassandraMailboxPathDAO {
     }
 
     @Override
-    public CompletableFuture<Void> delete(MailboxPath mailboxPath) {
-        return cassandraAsyncExecutor.executeVoid(delete.bind()
+    public Mono<Void> delete(MailboxPath mailboxPath) {
+        return cassandraAsyncExecutor.executeVoidReactor(delete.bind()
             .setUDTValue(NAMESPACE_AND_USER, mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), mailboxPath.getUser()))
             .setString(MAILBOX_NAME, mailboxPath.getName()));
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV2DAO.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV2DAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV2DAO.java
index 1f58898..2247c66 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV2DAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathV2DAO.java
@@ -31,10 +31,6 @@ import static org.apache.james.mailbox.cassandra.table.CassandraMailboxPathV2Tab
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxPathV2Table.TABLE_NAME;
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxPathV2Table.USER;
 
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
@@ -42,11 +38,15 @@ import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.mailbox.cassandra.GhostMailbox;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.util.FunctionalUtils;
+import org.apache.james.util.ReactorUtils;
 
 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 reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraMailboxPathV2DAO implements CassandraMailboxPathDAO {
 
@@ -101,26 +101,26 @@ public class CassandraMailboxPathV2DAO implements CassandraMailboxPathDAO {
     }
 
     @Override
-    public CompletableFuture<Optional<CassandraIdAndPath>> retrieveId(MailboxPath mailboxPath) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    public Mono<CassandraIdAndPath> retrieveId(MailboxPath mailboxPath) {
+        return cassandraAsyncExecutor.executeSingleRowReactor(
             select.bind()
                 .setString(NAMESPACE, mailboxPath.getNamespace())
                 .setString(USER, sanitizeUser(mailboxPath.getUser()))
                 .setString(MAILBOX_NAME, mailboxPath.getName()))
-            .thenApply(rowOptional ->
-                rowOptional.map(this::fromRowToCassandraIdAndPath))
-            .thenApply(value -> logGhostMailbox(mailboxPath, value));
+            .map(this::fromRowToCassandraIdAndPath)
+            .map(FunctionalUtils.toFunction(this::logGhostMailboxSuccess))
+            .switchIfEmpty(ReactorUtils.executeAndEmpty(() -> logGhostMailboxFailure(mailboxPath)));
     }
 
     @Override
-    public CompletableFuture<Stream<CassandraIdAndPath>> listUserMailboxes(String namespace, String user) {
-        return cassandraAsyncExecutor.execute(
+    public Flux<CassandraIdAndPath> listUserMailboxes(String namespace, String user) {
+        return cassandraAsyncExecutor.executeReactor(
             selectAll.bind()
                 .setString(NAMESPACE, namespace)
                 .setString(USER, sanitizeUser(user)))
-            .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet)
+            .flatMapMany(resultSet -> cassandraUtils.convertToFlux(resultSet)
                 .map(this::fromRowToCassandraIdAndPath)
-                .peek(this::logReadSuccess));
+                .map(FunctionalUtils.toFunction(this::logReadSuccess)));
     }
 
     /**
@@ -130,17 +130,16 @@ public class CassandraMailboxPathV2DAO implements CassandraMailboxPathDAO {
      * reads and write operations are also added in order to allow audit in order to know if the mailbox existed.
      */
     @Override
-    public Optional<CassandraIdAndPath> logGhostMailbox(MailboxPath mailboxPath, Optional<CassandraIdAndPath> value) {
-        if (value.isPresent()) {
-            CassandraIdAndPath cassandraIdAndPath = value.get();
-            logReadSuccess(cassandraIdAndPath);
-        } else {
-            GhostMailbox.logger()
+    public void logGhostMailboxSuccess(CassandraIdAndPath value) {
+        logReadSuccess(value);
+    }
+
+    @Override
+    public void logGhostMailboxFailure(MailboxPath mailboxPath) {
+        GhostMailbox.logger()
                 .addField(GhostMailbox.MAILBOX_NAME, mailboxPath)
                 .addField(TYPE, "readMiss")
                 .log(logger -> logger.info("Read mailbox missed"));
-        }
-        return value;
     }
 
     /**
@@ -166,7 +165,7 @@ public class CassandraMailboxPathV2DAO implements CassandraMailboxPathDAO {
     }
 
     @Override
-    public CompletableFuture<Boolean> save(MailboxPath mailboxPath, CassandraId mailboxId) {
+    public Mono<Boolean> save(MailboxPath mailboxPath, CassandraId mailboxId) {
         return cassandraAsyncExecutor.executeReturnApplied(insert.bind()
             .setString(NAMESPACE, mailboxPath.getNamespace())
             .setString(USER, sanitizeUser(mailboxPath.getUser()))
@@ -175,8 +174,8 @@ public class CassandraMailboxPathV2DAO implements CassandraMailboxPathDAO {
     }
 
     @Override
-    public CompletableFuture<Void> delete(MailboxPath mailboxPath) {
-        return cassandraAsyncExecutor.executeVoid(delete.bind()
+    public Mono<Void> delete(MailboxPath mailboxPath) {
+        return cassandraAsyncExecutor.executeVoidReactor(delete.bind()
             .setString(NAMESPACE, mailboxPath.getNamespace())
             .setString(USER, sanitizeUser(mailboxPath.getUser()))
             .setString(MAILBOX_NAME, mailboxPath.getName()));


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


[11/12] james-project git commit: JAMES-2630 Improve ConcurrentTestRunner reporting

Posted by ma...@apache.org.
JAMES-2630 Improve ConcurrentTestRunner reporting


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/64d33771
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/64d33771
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/64d33771

Branch: refs/heads/master
Commit: 64d337713f91afd7d5a9b257afb8532adaa17b42
Parents: e4a737e
Author: Matthieu Baechler <ma...@apache.org>
Authored: Fri Jan 18 11:47:31 2019 +0100
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Mon Jan 28 15:50:37 2019 +0100

----------------------------------------------------------------------
 .../org/apache/james/util/concurrency/ConcurrentTestRunner.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/64d33771/server/container/util/src/main/java/org/apache/james/util/concurrency/ConcurrentTestRunner.java
----------------------------------------------------------------------
diff --git a/server/container/util/src/main/java/org/apache/james/util/concurrency/ConcurrentTestRunner.java b/server/container/util/src/main/java/org/apache/james/util/concurrency/ConcurrentTestRunner.java
index eec20c0..080198d 100644
--- a/server/container/util/src/main/java/org/apache/james/util/concurrency/ConcurrentTestRunner.java
+++ b/server/container/util/src/main/java/org/apache/james/util/concurrency/ConcurrentTestRunner.java
@@ -111,7 +111,7 @@ public class ConcurrentTestRunner {
                 try {
                     concurrentOperation.execute(threadNumber, i);
                 } catch (Exception e) {
-                    LOGGER.error("Error caught during concurrent testing", e);
+                    LOGGER.error("Error caught during concurrent testing (iteration {}, threadNumber {})", i, threadNumber, e);
                     exception = e;
                 }
             }


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


[04/12] james-project git commit: JAMES-2630 Port CassandraMessageMapper to Reactor

Posted by ma...@apache.org.
JAMES-2630 Port CassandraMessageMapper to Reactor


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/1295a89b
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/1295a89b
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/1295a89b

Branch: refs/heads/master
Commit: 1295a89b3cf63106dadfa7d4e9c859a38c9618eb
Parents: 2133f0b
Author: Matthieu Baechler <ma...@apache.org>
Authored: Sun Nov 25 16:06:06 2018 +0100
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Mon Jan 28 15:30:53 2019 +0100

----------------------------------------------------------------------
 .../cassandra/mail/CassandraMessageMapper.java  | 190 ++++++++++---------
 1 file changed, 100 insertions(+), 90 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/1295a89b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
----------------------------------------------------------------------
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 59d9a1e..0133f05 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
@@ -26,7 +26,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
 
 import javax.mail.Flags;
 import javax.mail.Flags.Flag;
@@ -51,9 +50,7 @@ import org.apache.james.mailbox.store.mail.MessageMapper;
 import org.apache.james.mailbox.store.mail.model.Mailbox;
 import org.apache.james.mailbox.store.mail.model.MailboxMessage;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
-import org.apache.james.util.FluentFutureStream;
 import org.apache.james.util.OptionalUtils;
-import org.apache.james.util.streams.JamesCollectors;
 import org.apache.james.util.streams.Limit;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -61,6 +58,8 @@ import org.slf4j.LoggerFactory;
 import com.github.fge.lambdas.Throwing;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableList;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraMessageMapper implements MessageMapper {
     public static final MailboxCounters INITIAL_COUNTERS =  MailboxCounters.builder()
@@ -140,33 +139,34 @@ public class CassandraMessageMapper implements MessageMapper {
     @Override
     public void delete(Mailbox mailbox, MailboxMessage message) {
         deleteAsFuture(message)
-            .join();
+            .block();
     }
 
-    private CompletableFuture<Void> deleteAsFuture(MailboxMessage message) {
+    private Mono<Void> deleteAsFuture(MailboxMessage message) {
         ComposedMessageIdWithMetaData composedMessageIdWithMetaData = message.getComposedMessageIdWithMetaData();
 
         return deleteUsingMailboxId(composedMessageIdWithMetaData);
     }
 
-    private CompletableFuture<Void> deleteUsingMailboxId(ComposedMessageIdWithMetaData composedMessageIdWithMetaData) {
+    private Mono<Void> deleteUsingMailboxId(ComposedMessageIdWithMetaData composedMessageIdWithMetaData) {
         ComposedMessageId composedMessageId = composedMessageIdWithMetaData.getComposedMessageId();
         CassandraMessageId messageId = (CassandraMessageId) composedMessageId.getMessageId();
         CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
         MessageUid uid = composedMessageId.getUid();
-        return CompletableFuture.allOf(
-            imapUidDAO.delete(messageId, mailboxId),
-            messageIdDAO.delete(mailboxId, uid)
-        ).thenCompose(voidValue -> indexTableHandler.updateIndexOnDelete(composedMessageIdWithMetaData, mailboxId));
+        return Flux.merge(
+                Mono.fromCompletionStage(imapUidDAO.delete(messageId, mailboxId)),
+                Mono.fromCompletionStage(messageIdDAO.delete(mailboxId, uid)))
+            .concatWith(Mono.fromCompletionStage(indexTableHandler.updateIndexOnDelete(composedMessageIdWithMetaData, mailboxId)))
+            .last();
     }
 
     @Override
     public Iterator<MailboxMessage> findInMailbox(Mailbox mailbox, MessageRange messageRange, FetchType ftype, int max) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
         return retrieveMessages(retrieveMessageIds(mailboxId, messageRange), ftype, Limit.from(max))
-            .join()
             .map(SimpleMailboxMessage -> (MailboxMessage) SimpleMailboxMessage)
-            .sorted(Comparator.comparing(MailboxMessage::getUid))
+            .sort(Comparator.comparing(MailboxMessage::getUid))
+            .toIterable()
             .iterator();
     }
 
@@ -176,12 +176,13 @@ public class CassandraMessageMapper implements MessageMapper {
             .collect(Guavate.toImmutableList());
     }
 
-    private CompletableFuture<Stream<SimpleMailboxMessage>> retrieveMessages(List<ComposedMessageIdWithMetaData> messageIds, FetchType fetchType, Limit limit) {
-        return messageDAO.retrieveMessages(messageIds, fetchType, limit)
-            .thenApply(steam -> steam
+    private Flux<SimpleMailboxMessage> retrieveMessages(List<ComposedMessageIdWithMetaData> messageIds, FetchType fetchType, Limit limit) {
+        return Mono.fromCompletionStage(messageDAO.retrieveMessages(messageIds, fetchType, limit))
+            .map(stream -> stream
                 .filter(CassandraMessageDAO.MessageResult::isFound)
                 .map(CassandraMessageDAO.MessageResult::message))
-            .thenCompose(stream -> attachmentLoader.addAttachmentToMessages(stream, fetchType));
+            .flatMap(stream -> Mono.fromCompletionStage(attachmentLoader.addAttachmentToMessages(stream, fetchType)))
+            .flatMapMany(Flux::fromStream);
     }
 
     @Override
@@ -204,32 +205,31 @@ public class CassandraMessageMapper implements MessageMapper {
     public Map<MessageUid, MessageMetaData> expungeMarkedForDeletionInMailbox(Mailbox mailbox, MessageRange messageRange) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
-        return deletedMessageDAO.retrieveDeletedMessage(mailboxId, messageRange)
-            .join()
-            .collect(JamesCollectors.chunker(cassandraConfiguration.getExpungeChunkSize()))
-            .map(uidChunk -> expungeUidChunk(mailboxId, uidChunk))
-            .flatMap(CompletableFuture::join)
-            .collect(Guavate.toImmutableMap(MailboxMessage::getUid, MailboxMessage::metaData));
-    }
-
-    private CompletableFuture<Stream<SimpleMailboxMessage>> expungeUidChunk(CassandraId mailboxId, Collection<MessageUid> uidChunk) {
-        return FluentFutureStream.of(
-                uidChunk.stream().map(uid -> retrieveComposedId(mailboxId, uid)),
-                FluentFutureStream::unboxOptional)
-            .performOnAll(this::deleteUsingMailboxId)
-            .map(idWithMetadata -> FluentFutureStream.of(
-                messageDAO.retrieveMessages(ImmutableList.of(idWithMetadata), FetchType.Metadata, Limit.unlimited())),
-                FluentFutureStream::unboxFluentFuture)
+        return Mono.fromCompletionStage(deletedMessageDAO.retrieveDeletedMessage(mailboxId, messageRange))
+            .flatMapMany(Flux::fromStream)
+            .buffer(cassandraConfiguration.getExpungeChunkSize())
+            .flatMap(uidChunk -> expungeUidChunk(mailboxId, uidChunk))
+            .collect(Guavate.<SimpleMailboxMessage, MessageUid, MessageMetaData>toImmutableMap(MailboxMessage::getUid, MailboxMessage::metaData))
+            .block();
+    }
+
+    private Flux<SimpleMailboxMessage> expungeUidChunk(CassandraId mailboxId, Collection<MessageUid> uidChunk) {
+        return Flux.fromStream(uidChunk.stream())
+            .flatMap(uid -> retrieveComposedId(mailboxId, uid))
+            .doOnNext(this::deleteUsingMailboxId)
+            .flatMap(idWithMetadata ->
+                Mono.fromCompletionStage(messageDAO.retrieveMessages(ImmutableList.of(idWithMetadata), FetchType.Metadata, Limit.unlimited())))
+            .flatMap(Flux::fromStream)
             .filter(CassandraMessageDAO.MessageResult::isFound)
             .map(CassandraMessageDAO.MessageResult::message)
-            .map(pair -> pair.getKey().toMailboxMessage(ImmutableList.of()))
-            .completableFuture();
+            .map(pair -> pair.getKey().toMailboxMessage(ImmutableList.of()));
     }
 
-    private CompletableFuture<Optional<ComposedMessageIdWithMetaData>> retrieveComposedId(CassandraId mailboxId, MessageUid uid) {
-        return messageIdDAO.retrieve(mailboxId, uid)
-            .thenApply(optional -> OptionalUtils.executeIfEmpty(optional,
-                () -> LOGGER.warn("Could not retrieve message {} {}", mailboxId, uid)));
+    private Mono<ComposedMessageIdWithMetaData> retrieveComposedId(CassandraId mailboxId, MessageUid uid) {
+        return Mono.fromCompletionStage(messageIdDAO.retrieve(mailboxId, uid))
+            .doOnNext(optional -> OptionalUtils.executeIfEmpty(optional,
+                () -> LOGGER.warn("Could not retrieve message {} {}", mailboxId, uid)))
+            .flatMap(Mono::justOrEmpty);
     }
 
     @Override
@@ -237,7 +237,7 @@ public class CassandraMessageMapper implements MessageMapper {
         ComposedMessageIdWithMetaData composedMessageIdWithMetaData = original.getComposedMessageIdWithMetaData();
 
         MessageMetaData messageMetaData = copy(destinationMailbox, original);
-        deleteUsingMailboxId(composedMessageIdWithMetaData).join();
+        deleteUsingMailboxId(composedMessageIdWithMetaData).block();
 
         return messageMetaData;
     }
@@ -257,8 +257,8 @@ public class CassandraMessageMapper implements MessageMapper {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
         save(mailbox, addUidAndModseq(message, mailboxId))
-            .thenCompose(voidValue -> indexTableHandler.updateIndexOnAdd(message, mailboxId))
-            .join();
+            .map(voidValue -> indexTableHandler.updateIndexOnAdd(message, mailboxId))
+            .block();
         return message.metaData();
     }
 
@@ -279,9 +279,10 @@ public class CassandraMessageMapper implements MessageMapper {
     public Iterator<UpdatedFlags> updateFlags(Mailbox mailbox, FlagsUpdateCalculator flagUpdateCalculator, MessageRange range) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
-        Stream<ComposedMessageIdWithMetaData> toBeUpdated = messageIdDAO.retrieveMessages(mailboxId, range).join();
+        Flux<ComposedMessageIdWithMetaData> toBeUpdated = Mono.fromCompletionStage(messageIdDAO.retrieveMessages(mailboxId, range))
+            .flatMapMany(Flux::fromStream);
 
-        FlagsUpdateStageResult firstResult = runUpdateStage(mailboxId, toBeUpdated, flagUpdateCalculator);
+        FlagsUpdateStageResult firstResult = runUpdateStage(mailboxId, toBeUpdated, flagUpdateCalculator).block();
         FlagsUpdateStageResult finalResult = handleUpdatesStagedRetry(mailboxId, flagUpdateCalculator, firstResult);
         if (finalResult.containsFailedResults()) {
             LOGGER.error("Can not update following UIDs {} for mailbox {}", finalResult.getFailed(), mailboxId.asUuid());
@@ -294,50 +295,55 @@ public class CassandraMessageMapper implements MessageMapper {
         int retryCount = 0;
         while (retryCount < cassandraConfiguration.getFlagsUpdateMessageMaxRetry() && globalResult.containsFailedResults()) {
             retryCount++;
-            FlagsUpdateStageResult stageResult = retryUpdatesStage(mailboxId, flagUpdateCalculator, globalResult.getFailed());
+            FlagsUpdateStageResult stageResult = retryUpdatesStage(mailboxId, flagUpdateCalculator, globalResult.getFailed()).block();
             globalResult = globalResult.keepSucceded().merge(stageResult);
         }
         return globalResult;
     }
 
-    private FlagsUpdateStageResult retryUpdatesStage(CassandraId mailboxId, FlagsUpdateCalculator flagsUpdateCalculator, List<MessageUid> failed) {
-        Stream<ComposedMessageIdWithMetaData> idsFailed = FluentFutureStream.of(
-                failed.stream().map(uid -> messageIdDAO.retrieve(mailboxId, uid)),
-                FluentFutureStream::unboxOptional)
-            .join();
-
-        return runUpdateStage(mailboxId, idsFailed, flagsUpdateCalculator);
+    private Mono<FlagsUpdateStageResult> retryUpdatesStage(CassandraId mailboxId, FlagsUpdateCalculator flagsUpdateCalculator, List<MessageUid> failed) {
+        if (!failed.isEmpty()) {
+            Flux<ComposedMessageIdWithMetaData> toUpdate = Flux.fromIterable(failed)
+                .flatMap(uid ->
+                    Mono.fromCompletionStage(messageIdDAO.retrieve(mailboxId, uid))
+                        .flatMap(Mono::justOrEmpty)
+                );
+            return runUpdateStage(mailboxId, toUpdate, flagsUpdateCalculator);
+        } else {
+            return Mono.empty();
+        }
     }
 
-    private FlagsUpdateStageResult runUpdateStage(CassandraId mailboxId, Stream<ComposedMessageIdWithMetaData> toBeUpdated, FlagsUpdateCalculator flagsUpdateCalculator) {
-        Long newModSeq = modSeqProvider.nextModSeq(mailboxId).join().orElseThrow(() -> new RuntimeException("ModSeq generation failed for mailbox " + mailboxId.asUuid()));
-
-        return toBeUpdated.collect(JamesCollectors.chunker(cassandraConfiguration.getFlagsUpdateChunkSize()))
-            .map(uidChunk -> performUpdatesForChunk(mailboxId, flagsUpdateCalculator, newModSeq, uidChunk))
-            .map(CompletableFuture::join)
+    private Mono<FlagsUpdateStageResult> runUpdateStage(CassandraId mailboxId, Flux<ComposedMessageIdWithMetaData> toBeUpdated, FlagsUpdateCalculator flagsUpdateCalculator) {
+        Mono<Long> newModSeq = computeNewModSeq(mailboxId);
+        return toBeUpdated
+            .buffer(cassandraConfiguration.getFlagsUpdateChunkSize())
+            .flatMap(uidChunk -> newModSeq.flatMap(modSeq -> performUpdatesForChunk(mailboxId, flagsUpdateCalculator, modSeq, uidChunk)))
             .reduce(FlagsUpdateStageResult.none(), FlagsUpdateStageResult::merge);
     }
 
-    private CompletableFuture<FlagsUpdateStageResult> performUpdatesForChunk(CassandraId mailboxId, FlagsUpdateCalculator flagsUpdateCalculator, Long newModSeq, Collection<ComposedMessageIdWithMetaData> uidChunk) {
-        Stream<CompletableFuture<FlagsUpdateStageResult>> updateMetaDataFuture =
-            uidChunk.stream().map(oldMetadata -> tryFlagsUpdate(flagsUpdateCalculator, newModSeq, oldMetadata));
+    private Mono<Long> computeNewModSeq(CassandraId mailboxId) {
+        return Mono.fromCompletionStage(modSeqProvider.nextModSeq(mailboxId))
+            .map(value -> value.orElseThrow(() -> new RuntimeException("ModSeq generation failed for mailbox " + mailboxId.asUuid())));
+    }
 
-        return FluentFutureStream.of(updateMetaDataFuture)
+    private Mono<FlagsUpdateStageResult> performUpdatesForChunk(CassandraId mailboxId, FlagsUpdateCalculator flagsUpdateCalculator, Long newModSeq, Collection<ComposedMessageIdWithMetaData> uidChunk) {
+        return Flux.fromIterable(uidChunk)
+            .flatMap(oldMetadata -> tryFlagsUpdate(flagsUpdateCalculator, newModSeq, oldMetadata))
             .reduce(FlagsUpdateStageResult.none(), FlagsUpdateStageResult::merge)
-            .thenCompose(result -> updateIndexesForUpdatesResult(mailboxId, result));
+            .flatMap(result -> updateIndexesForUpdatesResult(mailboxId, result));
     }
 
-    private CompletableFuture<FlagsUpdateStageResult> updateIndexesForUpdatesResult(CassandraId mailboxId, FlagsUpdateStageResult result) {
-        return FluentFutureStream.of(
-            result.getSucceeded().stream()
-                .map(Throwing
-                    .function((UpdatedFlags updatedFlags) -> indexTableHandler.updateIndexOnFlagsUpdate(mailboxId, updatedFlags))
-                    .fallbackTo(failedindex -> {
-                        LOGGER.error("Could not update flag indexes for mailboxId {} UID {}. This will lead to inconsistencies across Cassandra tables", mailboxId, failedindex.getUid());
-                        return CompletableFuture.completedFuture(null);
-                    })))
-            .completableFuture()
-            .thenApply(any -> result);
+    private Mono<FlagsUpdateStageResult> updateIndexesForUpdatesResult(CassandraId mailboxId, FlagsUpdateStageResult result) {
+        return Flux.fromIterable(result.getSucceeded())
+            .flatMap(Throwing
+                .function((UpdatedFlags updatedFlags) -> Mono.fromCompletionStage(indexTableHandler.updateIndexOnFlagsUpdate(mailboxId, updatedFlags)))
+                .fallbackTo(failedindex -> {
+                    LOGGER.error("Could not update flag indexes for mailboxId {} UID {}. This will lead to inconsistencies across Cassandra tables", mailboxId, failedindex.getUid());
+                    return Mono.just(null);
+                }))
+            .collectList()
+            .map(any -> result);
     }
 
     @Override
@@ -369,34 +375,36 @@ public class CassandraMessageMapper implements MessageMapper {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
 
         insertIds(addUidAndModseq(message, mailboxId), mailboxId)
-                .thenCompose(voidValue -> indexTableHandler.updateIndexOnAdd(message, mailboxId))
-                .join();
+                .map(voidValue -> indexTableHandler.updateIndexOnAdd(message, mailboxId))
+                .block();
         return message.metaData();
     }
 
-    private CompletableFuture<Void> save(Mailbox mailbox, MailboxMessage message) throws MailboxException {
+    private Mono<Void> save(Mailbox mailbox, MailboxMessage message) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
         return messageDAO.save(message)
-            .thenCompose(aVoid -> insertIds(message, mailboxId));
+            .flatMap(aVoid -> insertIds(message, mailboxId));
     }
 
-    private CompletableFuture<Void> insertIds(MailboxMessage message, CassandraId mailboxId) {
+    private Mono<Void> insertIds(MailboxMessage message, CassandraId mailboxId) {
         ComposedMessageIdWithMetaData composedMessageIdWithMetaData = ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(mailboxId, message.getMessageId(), message.getUid()))
                 .flags(message.createFlags())
                 .modSeq(message.getModSeq())
                 .build();
-        return CompletableFuture.allOf(messageIdDAO.insert(composedMessageIdWithMetaData),
-                imapUidDAO.insert(composedMessageIdWithMetaData));
+        return Flux.merge(
+            Mono.fromCompletionStage(messageIdDAO.insert(composedMessageIdWithMetaData)),
+            Mono.fromCompletionStage(imapUidDAO.insert(composedMessageIdWithMetaData)))
+            .last();
     }
 
 
-    private CompletableFuture<FlagsUpdateStageResult> tryFlagsUpdate(FlagsUpdateCalculator flagUpdateCalculator, long newModSeq, ComposedMessageIdWithMetaData oldMetaData) {
+    private Mono<FlagsUpdateStageResult> tryFlagsUpdate(FlagsUpdateCalculator flagUpdateCalculator, long newModSeq, ComposedMessageIdWithMetaData oldMetaData) {
         Flags oldFlags = oldMetaData.getFlags();
         Flags newFlags = flagUpdateCalculator.buildNewFlags(oldFlags);
 
         if (identicalFlags(oldFlags, newFlags)) {
-            return CompletableFuture.completedFuture(FlagsUpdateStageResult.success(UpdatedFlags.builder()
+            return Mono.just(FlagsUpdateStageResult.success(UpdatedFlags.builder()
                 .uid(oldMetaData.getComposedMessageId().getUid())
                 .modSeq(oldMetaData.getModSeq())
                 .oldFlags(oldFlags)
@@ -405,7 +413,7 @@ public class CassandraMessageMapper implements MessageMapper {
         }
 
         return updateFlags(oldMetaData, newFlags, newModSeq)
-            .thenApply(success -> {
+            .map(success -> {
                 if (success) {
                     return FlagsUpdateStageResult.success(UpdatedFlags.builder()
                         .uid(oldMetaData.getComposedMessageId().getUid())
@@ -423,17 +431,19 @@ public class CassandraMessageMapper implements MessageMapper {
         return oldFlags.equals(newFlags);
     }
 
-    private CompletableFuture<Boolean> updateFlags(ComposedMessageIdWithMetaData oldMetadata, Flags newFlags, long newModSeq) {
+    private Mono<Boolean> updateFlags(ComposedMessageIdWithMetaData oldMetadata, Flags newFlags, long newModSeq) {
         ComposedMessageIdWithMetaData newMetadata = ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(oldMetadata.getComposedMessageId())
                 .modSeq(newModSeq)
                 .flags(newFlags)
                 .build();
-        return imapUidDAO.updateMetadata(newMetadata, oldMetadata.getModSeq())
-            .thenCompose(success -> Optional.of(success)
-                .filter(b -> b)
-                .map((Boolean any) -> messageIdDAO.updateMetadata(newMetadata)
-                    .thenApply(v -> success))
-                .orElse(CompletableFuture.completedFuture(success)));
+        return Mono.fromCompletionStage(imapUidDAO.updateMetadata(newMetadata, oldMetadata.getModSeq()))
+            .flatMap(success -> {
+                if (success) {
+                    return Mono.fromCompletionStage(messageIdDAO.updateMetadata(newMetadata))
+                        .map(ignored -> true);
+                } else {
+                    return Mono.just(false);
+                }});
     }
 }


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


[07/12] james-project git commit: JAMES-2630 Migrate CassandraAsyncExecutor.executeReturnApplied consumers to Reactor

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java
index 2fd0426..df5dccc 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java
@@ -49,15 +49,15 @@ class CassandraActiveScriptDAOTest {
 
     @Test
     void getActiveSctiptInfoShouldReturnEmptyByDefault() {
-        assertThat(activeScriptDAO.getActiveSctiptInfo(USER).join().isPresent())
+        assertThat(activeScriptDAO.getActiveSctiptInfo(USER).blockOptional().isPresent())
             .isFalse();
     }
 
     @Test
     void getActiveSctiptInfoShouldReturnStoredName() {
-        activeScriptDAO.activate(USER, SCRIPT_NAME).join();
+        activeScriptDAO.activate(USER, SCRIPT_NAME).block();
 
-        Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).join();
+        Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).blockOptional();
 
         assertThat(actual.isPresent()).isTrue();
         assertThat(actual.get().getName()).isEqualTo(SCRIPT_NAME);
@@ -65,30 +65,30 @@ class CassandraActiveScriptDAOTest {
 
     @Test
     void activateShouldAllowRename() {
-        activeScriptDAO.activate(USER, SCRIPT_NAME).join();
+        activeScriptDAO.activate(USER, SCRIPT_NAME).block();
 
-        activeScriptDAO.activate(USER, NEW_SCRIPT_NAME).join();
+        activeScriptDAO.activate(USER, NEW_SCRIPT_NAME).block();
 
-        Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).join();
+        Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).blockOptional();
         assertThat(actual.isPresent()).isTrue();
         assertThat(actual.get().getName()).isEqualTo(NEW_SCRIPT_NAME);
     }
 
     @Test
     void unactivateShouldAllowRemovingActiveScript() {
-        activeScriptDAO.activate(USER, SCRIPT_NAME).join();
+        activeScriptDAO.activate(USER, SCRIPT_NAME).block();
 
-        activeScriptDAO.unactivate(USER).join();
+        activeScriptDAO.unactivate(USER).block();
 
-        Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).join();
+        Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).blockOptional();
         assertThat(actual.isPresent()).isFalse();
     }
 
     @Test
     void unactivateShouldWorkWhenNoneStore() {
-        activeScriptDAO.unactivate(USER).join();
+        activeScriptDAO.unactivate(USER).block();
 
-        Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).join();
+        Optional<ActiveScriptInfo> actual = activeScriptDAO.getActiveSctiptInfo(USER).blockOptional();
         assertThat(actual.isPresent()).isFalse();
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
index 5d38f61..5e3150d 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
@@ -70,54 +70,54 @@ class CassandraSieveDAOTest {
     
      @Test
     void getScriptShouldReturnEmptyByDefault() {
-        assertThat(sieveDAO.getScript(USER, SCRIPT_NAME).join().isPresent())
-            .isFalse();
+        assertThat(sieveDAO.getScript(USER, SCRIPT_NAME).blockOptional())
+            .isEmpty();
     }
 
     @Test
     void getScriptShouldReturnStoredScript() {
-        sieveDAO.insertScript(USER, SCRIPT).join();
+        sieveDAO.insertScript(USER, SCRIPT).block();
 
-        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join();
+        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).blockOptional();
 
         assertThat(actual).contains(SCRIPT);
     }
 
     @Test
     void insertScriptShouldUpdateContent() {
-        sieveDAO.insertScript(USER, SCRIPT).join();
+        sieveDAO.insertScript(USER, SCRIPT).block();
 
-        sieveDAO.insertScript(USER, SCRIPT_NEW_CONTENT).join();
+        sieveDAO.insertScript(USER, SCRIPT_NEW_CONTENT).block();
 
-        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join();
+        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).blockOptional();
         assertThat(actual).contains(SCRIPT_NEW_CONTENT);
     }
 
     @Test
     void insertScriptShouldUpdateActivate() {
-        sieveDAO.insertScript(USER, SCRIPT).join();
+        sieveDAO.insertScript(USER, SCRIPT).block();
 
-        sieveDAO.insertScript(USER, ACTIVE_SCRIPT).join();
+        sieveDAO.insertScript(USER, ACTIVE_SCRIPT).block();
 
-        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join();
+        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).blockOptional();
         assertThat(actual).contains(ACTIVE_SCRIPT);
     }
 
     @Test
     void deleteScriptInCassandraShouldWork() {
-        sieveDAO.insertScript(USER, SCRIPT).join();
+        sieveDAO.insertScript(USER, SCRIPT).block();
 
-        sieveDAO.deleteScriptInCassandra(USER, SCRIPT_NAME).join();
+        sieveDAO.deleteScriptInCassandra(USER, SCRIPT_NAME).block();
 
-        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join();
+        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).blockOptional();
         assertThat(actual).isEmpty();
     }
 
     @Test
     void deleteScriptInCassandraShouldWorkWhenNoneStore() {
-        sieveDAO.deleteScriptInCassandra(USER, SCRIPT_NAME).join();
+        sieveDAO.deleteScriptInCassandra(USER, SCRIPT_NAME).block();
 
-        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join();
+        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).blockOptional();
         assertThat(actual).isEmpty();
     }
 
@@ -130,8 +130,8 @@ class CassandraSieveDAOTest {
 
     @Test
     void listScriptsShouldReturnSingleStoredValue() {
-        sieveDAO.insertScript(USER, SCRIPT).join();
-        sieveDAO.insertScript(USER, SCRIPT2).join();
+        sieveDAO.insertScript(USER, SCRIPT).block();
+        sieveDAO.insertScript(USER, SCRIPT2).block();
 
         List<ScriptSummary> scriptSummaryList = sieveDAO.listScripts(USER).join();
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
index adca5b0..7cacb55 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
@@ -116,7 +116,7 @@ class CassandraSieveQuotaDAOTest {
     void spaceUsedByShouldReturnStoredValue() {
         long spaceUsed = 18L;
 
-        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join();
+        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).block();
 
         assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(spaceUsed);
     }
@@ -125,8 +125,8 @@ class CassandraSieveQuotaDAOTest {
     void updateSpaceUsedShouldBeAdditive() {
         long spaceUsed = 18L;
 
-        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join();
-        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join();
+        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).block();
+        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).block();
 
         assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(2 * spaceUsed);
     }
@@ -135,8 +135,8 @@ class CassandraSieveQuotaDAOTest {
     void updateSpaceUsedShouldWorkWithNegativeValues() {
         long spaceUsed = 18L;
 
-        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join();
-        sieveQuotaDAO.updateSpaceUsed(USER, -1 * spaceUsed).join();
+        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).block();
+        sieveQuotaDAO.updateSpaceUsed(USER, -1 * spaceUsed).block();
 
         assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(0L);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
index 6655798..6f005e8 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
@@ -22,7 +22,6 @@ package org.apache.james.mailrepository.cassandra;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
 
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
@@ -33,10 +32,11 @@ import org.apache.james.mailrepository.api.MailKey;
 import org.apache.james.mailrepository.api.MailRepository;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.util.CompletableFutureUtil;
-import org.apache.james.util.FluentFutureStream;
 import org.apache.mailet.Mail;
 
 import com.github.fge.lambdas.Throwing;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraMailRepository implements MailRepository {
 
@@ -60,28 +60,28 @@ public class CassandraMailRepository implements MailRepository {
     public MailKey store(Mail mail) throws MessagingException {
         MailKey mailKey = MailKey.forMail(mail);
 
-        mimeMessageStore.save(mail.getMessage())
+        Mono.fromFuture(mimeMessageStore.save(mail.getMessage())
             .thenCompose(Throwing.function(parts -> mailDAO.store(url, mail,
                 parts.getHeaderBlobId(),
-                parts.getBodyBlobId())))
-            .thenCompose(any -> keysDAO.store(url, mailKey))
-            .thenCompose(this::increaseSizeIfStored)
-            .join();
+                parts.getBodyBlobId()))))
+            .then(keysDAO.store(url, mailKey))
+            .flatMap(this::increaseSizeIfStored)
+            .block();
 
         return mailKey;
     }
 
-    private CompletionStage<Void> increaseSizeIfStored(Boolean isStored) {
+    private Mono<Void> increaseSizeIfStored(Boolean isStored) {
         if (isStored) {
             return countDAO.increment(url);
         }
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
     @Override
     public Iterator<MailKey> list() {
         return keysDAO.list(url)
-            .join()
+            .toIterable()
             .iterator();
     }
 
@@ -108,33 +108,34 @@ public class CassandraMailRepository implements MailRepository {
 
     @Override
     public void remove(Mail mail) {
-        removeAsync(MailKey.forMail(mail)).join();
+        removeAsync(MailKey.forMail(mail)).block();
     }
 
     @Override
     public void remove(Collection<Mail> toRemove) {
-        FluentFutureStream.of(toRemove.stream()
+        Flux.fromIterable(toRemove)
             .map(MailKey::forMail)
-            .map(this::removeAsync))
-            .join();
+            .flatMap(this::removeAsync)
+            .then()
+            .block();
     }
 
     @Override
     public void remove(MailKey key) {
-        removeAsync(key).join();
+        removeAsync(key).block();
     }
 
-    private CompletableFuture<Void> removeAsync(MailKey key) {
+    private Mono<Void> removeAsync(MailKey key) {
         return keysDAO.remove(url, key)
-            .thenCompose(this::decreaseSizeIfDeleted)
-            .thenCompose(any -> mailDAO.remove(url, key));
+            .flatMap(this::decreaseSizeIfDeleted)
+            .then(mailDAO.remove(url, key));
     }
 
-    private CompletionStage<Void> decreaseSizeIfDeleted(Boolean isDeleted) {
+    private Mono<Void> decreaseSizeIfDeleted(Boolean isDeleted) {
         if (isDeleted) {
             return countDAO.decrement(url);
         }
-        return CompletableFuture.completedFuture(null);
+        return Mono.empty();
     }
 
     @Override
@@ -145,9 +146,9 @@ public class CassandraMailRepository implements MailRepository {
     @Override
     public void removeAll() {
         keysDAO.list(url)
-            .thenCompose(stream -> FluentFutureStream.of(stream.map(this::removeAsync))
-                .completableFuture())
-            .join();
+            .flatMap(this::removeAsync)
+            .then()
+            .block();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAO.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAO.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAO.java
index cc2d4ea..540aa1a 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAO.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAO.java
@@ -40,6 +40,7 @@ import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
+import reactor.core.publisher.Mono;
 
 public class CassandraMailRepositoryCountDAO {
 
@@ -75,13 +76,13 @@ public class CassandraMailRepositoryCountDAO {
             .where(eq(REPOSITORY_NAME, bindMarker(REPOSITORY_NAME))));
     }
 
-    public CompletableFuture<Void> increment(MailRepositoryUrl url) {
-        return executor.executeVoid(increment.bind()
+    public Mono<Void> increment(MailRepositoryUrl url) {
+        return executor.executeVoidReactor(increment.bind()
             .setString(REPOSITORY_NAME, url.asString()));
     }
 
-    public CompletableFuture<Void> decrement(MailRepositoryUrl url) {
-        return executor.executeVoid(decrement.bind()
+    public Mono<Void> decrement(MailRepositoryUrl url) {
+        return executor.executeVoidReactor(decrement.bind()
             .setString(REPOSITORY_NAME, url.asString()));
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAO.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAO.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAO.java
index 93bffec..8bd5902 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAO.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAO.java
@@ -28,9 +28,6 @@ import static org.apache.james.mailrepository.cassandra.MailRepositoryTable.KEYS
 import static org.apache.james.mailrepository.cassandra.MailRepositoryTable.MAIL_KEY;
 import static org.apache.james.mailrepository.cassandra.MailRepositoryTable.REPOSITORY_NAME;
 
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
-
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
@@ -40,6 +37,8 @@ import org.apache.james.mailrepository.api.MailRepositoryUrl;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraMailRepositoryKeysDAO {
 
@@ -80,20 +79,20 @@ public class CassandraMailRepositoryKeysDAO {
             .value(MAIL_KEY, bindMarker(MAIL_KEY)));
     }
 
-    public CompletableFuture<Boolean> store(MailRepositoryUrl url, MailKey key) {
+    public Mono<Boolean> store(MailRepositoryUrl url, MailKey key) {
         return executor.executeReturnApplied(insertKey.bind()
             .setString(REPOSITORY_NAME, url.asString())
             .setString(MAIL_KEY, key.asString()));
     }
 
-    public CompletableFuture<Stream<MailKey>> list(MailRepositoryUrl url) {
-        return executor.execute(listKeys.bind()
+    public Flux<MailKey> list(MailRepositoryUrl url) {
+        return executor.executeReactor(listKeys.bind()
             .setString(REPOSITORY_NAME, url.asString()))
-            .thenApply(cassandraUtils::convertToStream)
-            .thenApply(stream -> stream.map(row -> new MailKey(row.getString(MAIL_KEY))));
+            .flatMapMany(cassandraUtils::convertToFlux)
+            .map(row -> new MailKey(row.getString(MAIL_KEY)));
     }
 
-    public CompletableFuture<Boolean> remove(MailRepositoryUrl url, MailKey key) {
+    public Mono<Boolean> remove(MailRepositoryUrl url, MailKey key) {
         return executor.executeReturnApplied(deleteKey.bind()
             .setString(REPOSITORY_NAME, url.asString())
             .setString(MAIL_KEY, key.asString()));

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
index 7c3596b..6e884b4 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAO.java
@@ -84,6 +84,7 @@ import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import reactor.core.publisher.Mono;
 
 public class CassandraMailRepositoryMailDAO implements CassandraMailRepositoryMailDaoAPI {
 
@@ -161,8 +162,8 @@ public class CassandraMailRepositoryMailDAO implements CassandraMailRepositoryMa
     }
 
     @Override
-    public CompletableFuture<Void> remove(MailRepositoryUrl url, MailKey key) {
-        return executor.executeVoid(deleteMail.bind()
+    public Mono<Void> remove(MailRepositoryUrl url, MailKey key) {
+        return executor.executeVoidReactor(deleteMail.bind()
             .setString(REPOSITORY_NAME, url.asString())
             .setString(MAIL_KEY, key.asString()));
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoAPI.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoAPI.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoAPI.java
index 435bcf1..bf49097 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoAPI.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoAPI.java
@@ -31,10 +31,12 @@ import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.server.core.MailImpl;
 import org.apache.mailet.Mail;
 
+import reactor.core.publisher.Mono;
+
 public interface CassandraMailRepositoryMailDaoAPI {
     CompletableFuture<Void> store(MailRepositoryUrl url, Mail mail, BlobId headerId, BlobId bodyId) throws MessagingException;
 
-    CompletableFuture<Void> remove(MailRepositoryUrl url, MailKey key);
+    Mono<Void> remove(MailRepositoryUrl url, MailKey key);
 
     CompletableFuture<Optional<MailDTO>> read(MailRepositoryUrl url, MailKey key);
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
index 36e8e28..5b4edfe 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java
@@ -79,6 +79,7 @@ import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import reactor.core.publisher.Mono;
 
 public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepositoryMailDaoAPI {
 
@@ -151,8 +152,9 @@ public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepository
         );
     }
 
-    public CompletableFuture<Void> remove(MailRepositoryUrl url, MailKey key) {
-        return executor.executeVoid(deleteMail.bind()
+    @Override
+    public Mono<Void> remove(MailRepositoryUrl url, MailKey key) {
+        return executor.executeVoidReactor(deleteMail.bind()
             .setString(REPOSITORY_NAME, url.asString())
             .setString(MAIL_KEY, key.asString()));
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MergingCassandraMailRepositoryMailDao.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MergingCassandraMailRepositoryMailDao.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MergingCassandraMailRepositoryMailDao.java
index 8b01a38..f83766a 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MergingCassandraMailRepositoryMailDao.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/MergingCassandraMailRepositoryMailDao.java
@@ -32,6 +32,8 @@ import org.apache.james.util.OptionalUtils;
 import org.apache.mailet.Mail;
 
 import com.google.common.annotations.VisibleForTesting;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class MergingCassandraMailRepositoryMailDao implements CassandraMailRepositoryMailDaoAPI {
 
@@ -51,8 +53,8 @@ public class MergingCassandraMailRepositoryMailDao implements CassandraMailRepos
     }
 
     @Override
-    public CompletableFuture<Void> remove(MailRepositoryUrl url, MailKey key) {
-        return CompletableFuture.allOf(v1.remove(url, key), v2.remove(url, key));
+    public Mono<Void> remove(MailRepositoryUrl url, MailKey key) {
+        return Flux.merge(v1.remove(url, key), v2.remove(url, key)).then();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAOTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAOTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAOTest.java
index 98b6fa2..32eb13d 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAOTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryCountDAOTest.java
@@ -50,7 +50,7 @@ class CassandraMailRepositoryCountDAOTest {
 
     @Test
     void getCountShouldReturnOneWhenIncrementedOneTime() {
-        testee.increment(URL).join();
+        testee.increment(URL).block();
 
         assertThat(testee.getCount(URL).join())
             .isEqualTo(1L);
@@ -58,7 +58,7 @@ class CassandraMailRepositoryCountDAOTest {
 
     @Test
     void incrementShouldNotAffectOtherUrls() {
-        testee.increment(URL).join();
+        testee.increment(URL).block();
 
         assertThat(testee.getCount(URL2).join())
             .isEqualTo(0L);
@@ -66,8 +66,8 @@ class CassandraMailRepositoryCountDAOTest {
 
     @Test
     void incrementCanBeAppliedSeveralTime() {
-        testee.increment(URL).join();
-        testee.increment(URL).join();
+        testee.increment(URL).block();
+        testee.increment(URL).block();
 
         assertThat(testee.getCount(URL).join())
             .isEqualTo(2L);
@@ -75,11 +75,11 @@ class CassandraMailRepositoryCountDAOTest {
 
     @Test
     void decrementShouldDecreaseCount() {
-        testee.increment(URL).join();
-        testee.increment(URL).join();
-        testee.increment(URL).join();
+        testee.increment(URL).block();
+        testee.increment(URL).block();
+        testee.increment(URL).block();
 
-        testee.decrement(URL).join();
+        testee.decrement(URL).block();
 
         assertThat(testee.getCount(URL).join())
             .isEqualTo(2L);
@@ -87,7 +87,7 @@ class CassandraMailRepositoryCountDAOTest {
 
     @Test
     void decrementCanLeadToNegativeCount() {
-        testee.decrement(URL).join();
+        testee.decrement(URL).block();
 
         assertThat(testee.getCount(URL).join())
             .isEqualTo(-1L);

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAOTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAOTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAOTest.java
index 3c457af..db7f98a 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAOTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryKeysDAOTest.java
@@ -23,7 +23,9 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.mailrepository.api.MailKey;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.junit.jupiter.api.BeforeEach;
@@ -36,9 +38,11 @@ class CassandraMailRepositoryKeysDAOTest {
     static final MailKey KEY_1 = new MailKey("key1");
     static final MailKey KEY_2 = new MailKey("key2");
     static final MailKey KEY_3 = new MailKey("key3");
+    static final CassandraModule MODULE = CassandraModule.aggregateModules(CassandraMailRepositoryModule.MODULE,
+            CassandraSchemaVersionModule.MODULE);
 
     @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraMailRepositoryModule.MODULE);
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULE);
 
     CassandraMailRepositoryKeysDAO testee;
 
@@ -49,75 +53,75 @@ class CassandraMailRepositoryKeysDAOTest {
 
     @Test
     void listShouldBeEmptyByDefault() {
-        assertThat(testee.list(URL).join())
+        assertThat(testee.list(URL).collectList().block())
             .isEmpty();
     }
 
     @Test
     void listShouldReturnEmptyByDefault() {
-        testee.store(URL, KEY_1).join();
+        testee.store(URL, KEY_1).block();
 
-        assertThat(testee.list(URL).join())
+        assertThat(testee.list(URL).collectList().block())
             .containsOnly(KEY_1);
     }
 
     @Test
     void listShouldNotReturnElementsOfOtherRepositories() {
-        testee.store(URL, KEY_1).join();
+        testee.store(URL, KEY_1).block();
 
-        assertThat(testee.list(URL2).join())
+        assertThat(testee.list(URL2).collectList().block())
             .isEmpty();
     }
 
     @Test
     void listShouldReturnSeveralElements() {
-        testee.store(URL, KEY_1).join();
-        testee.store(URL, KEY_2).join();
-        testee.store(URL, KEY_3).join();
+        testee.store(URL, KEY_1).block();
+        testee.store(URL, KEY_2).block();
+        testee.store(URL, KEY_3).block();
 
-        assertThat(testee.list(URL).join())
+        assertThat(testee.list(URL).collectList().block())
             .containsOnly(KEY_1, KEY_2, KEY_3);
     }
 
     @Test
     void listShouldNotReturnRemovedElements() {
-        testee.store(URL, KEY_1).join();
-        testee.store(URL, KEY_2).join();
-        testee.store(URL, KEY_3).join();
+        testee.store(URL, KEY_1).block();
+        testee.store(URL, KEY_2).block();
+        testee.store(URL, KEY_3).block();
 
-        testee.remove(URL, KEY_2).join();
+        testee.remove(URL, KEY_2).block();
 
-        assertThat(testee.list(URL).join())
+        assertThat(testee.list(URL).collectList().block())
             .containsOnly(KEY_1, KEY_3);
     }
 
     @Test
     void removeShouldBeIdempotent() {
-        testee.remove(URL, KEY_2).join();
+        testee.remove(URL, KEY_2).block();
     }
 
     @Test
     void removeShouldNotAffectOtherRepositories() {
-        testee.store(URL, KEY_1).join();
+        testee.store(URL, KEY_1).block();
 
-        testee.remove(URL2, KEY_2).join();
+        testee.remove(URL2, KEY_2).block();
 
-        assertThat(testee.list(URL).join())
+        assertThat(testee.list(URL).collectList().block())
             .containsOnly(KEY_1);
     }
 
     @Test
     void removeShouldReturnTrueWhenKeyDeleted() {
-        testee.store(URL, KEY_1).join();
+        testee.store(URL, KEY_1).block();
 
-        boolean isDeleted = testee.remove(URL, KEY_1).join();
+        boolean isDeleted = testee.remove(URL, KEY_1).block();
 
         assertThat(isDeleted).isTrue();
     }
 
     @Test
     void removeShouldReturnFalseWhenKeyNotDeleted() {
-        boolean isDeleted = testee.remove(URL2, KEY_2).join();
+        boolean isDeleted = testee.remove(URL2, KEY_2).block();
 
         assertThat(isDeleted).isFalse();
     }
@@ -125,16 +129,16 @@ class CassandraMailRepositoryKeysDAOTest {
 
     @Test
     void storeShouldReturnTrueWhenNotPreviouslyStored() {
-        boolean isStored = testee.store(URL, KEY_1).join();
+        boolean isStored = testee.store(URL, KEY_1).block();
 
         assertThat(isStored).isTrue();
     }
 
     @Test
     void storeShouldReturnFalseWhenPreviouslyStored() {
-        testee.store(URL, KEY_1).join();
+        testee.store(URL, KEY_1).block();
 
-        boolean isStored = testee.store(URL, KEY_1).join();
+        boolean isStored = testee.store(URL, KEY_1).block();
 
         assertThat(isStored).isFalse();
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
index 2377b6b..f597eff 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java
@@ -104,7 +104,7 @@ class CassandraMailRepositoryMailDAOTest {
                 blobIdBody)
                 .join();
 
-            testee.remove(URL, KEY_1).join();
+            testee.remove(URL, KEY_1).block();
 
             assertThat(testee.read(URL, KEY_1).join())
                 .isEmpty();
@@ -374,7 +374,7 @@ class CassandraMailRepositoryMailDAOTest {
                 blobIdBody2)
                 .join();
 
-            testee.remove(URL, KEY_1).join();
+            testee.remove(URL, KEY_1).block();
 
             Optional<CassandraMailRepositoryMailDaoAPI.MailDTO> v1Entry = v1.read(URL, KEY_1).join();
             Optional<CassandraMailRepositoryMailDaoAPI.MailDTO> v2Entry = v2.read(URL, KEY_1).join();

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
index ca2eb2c..b39ed2d 100644
--- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
+++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryWithFakeImplementationsTest.java
@@ -33,6 +33,7 @@ import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.blob.api.BlobId;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.api.Store;
@@ -56,17 +57,19 @@ import org.junit.jupiter.api.extension.ExtensionContext;
 import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Session;
 import com.google.common.collect.ImmutableList;
+import reactor.core.publisher.Mono;
 
 @ExtendWith(CassandraMailRepositoryWithFakeImplementationsTest.MailRepositoryCassandraClusterExtension.class)
 class CassandraMailRepositoryWithFakeImplementationsTest {
-    static final MailRepositoryUrl URL = MailRepositoryUrl.from("proto://url");
-    static final HashBlobId.Factory BLOB_ID_FACTORY = new HashBlobId.Factory();
+    private static final MailRepositoryUrl URL = MailRepositoryUrl.from("proto://url");
+    private static final HashBlobId.Factory BLOB_ID_FACTORY = new HashBlobId.Factory();
 
     static class MailRepositoryCassandraClusterExtension extends CassandraClusterExtension {
         public MailRepositoryCassandraClusterExtension() {
             super(CassandraModule.aggregateModules(
                     CassandraMailRepositoryModule.MODULE,
-                    CassandraBlobModule.MODULE));
+                    CassandraBlobModule.MODULE,
+                    CassandraSchemaVersionModule.MODULE));
         }
 
         @Override
@@ -122,7 +125,7 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
                     .isInstanceOf(RuntimeException.class)
                     .hasMessage("java.lang.RuntimeException: Expected failure while saving");
 
-            assertThat(keysDAO.list(URL).join()).isEmpty();
+            assertThat(keysDAO.list(URL).collectList().block()).isEmpty();
         }
     }
 
@@ -155,9 +158,9 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
             }
 
             @Override
-            public CompletableFuture<Void> remove(MailRepositoryUrl url, MailKey key) {
-                return CompletableFuture.supplyAsync(() -> {
-                    throw new RuntimeException("Expected failure while remeving mail parts");
+            public Mono<Void> remove(MailRepositoryUrl url, MailKey key) {
+                return Mono.fromCallable(() -> {
+                    throw new RuntimeException("Expected failure while removing mail parts");
                 });
 
             }
@@ -186,7 +189,7 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
                     .isInstanceOf(RuntimeException.class)
                     .hasMessage("java.lang.RuntimeException: Expected failure while storing mail parts");
 
-            assertThat(keysDAO.list(URL).join()).isEmpty();
+            assertThat(keysDAO.list(URL).collectList().block()).isEmpty();
         }
 
         @Test
@@ -234,8 +237,8 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
             }
 
             @Override
-            public CompletableFuture<Boolean> store(MailRepositoryUrl url, MailKey key) {
-                return CompletableFuture.supplyAsync(() -> {
+            public Mono<Boolean> store(MailRepositoryUrl url, MailKey key) {
+                return Mono.fromCallable(() -> {
                     throw new RuntimeException("Expected failure while storing keys");
                 });
             }
@@ -255,7 +258,7 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
 
             assertThatThrownBy(() -> cassandraMailRepository.store(mail))
                     .isInstanceOf(RuntimeException.class)
-                    .hasMessage("java.lang.RuntimeException: Expected failure while storing keys");
+                    .hasMessage("Expected failure while storing keys");
 
             assertThat(countDAO.getCount(URL).join()).isEqualTo(0);
         }
@@ -274,7 +277,7 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
 
             assertThatThrownBy(() -> cassandraMailRepository.store(mail))
                     .isInstanceOf(RuntimeException.class)
-                    .hasMessage("java.lang.RuntimeException: Expected failure while storing keys");
+                    .hasMessage("Expected failure while storing keys");
 
             ResultSet resultSet = cassandra.getConf().execute(select()
                     .from(BlobTable.TABLE_NAME));
@@ -295,7 +298,7 @@ class CassandraMailRepositoryWithFakeImplementationsTest {
 
             assertThatThrownBy(() -> cassandraMailRepository.store(mail))
                     .isInstanceOf(RuntimeException.class)
-                    .hasMessage("java.lang.RuntimeException: Expected failure while storing keys");
+                    .hasMessage("Expected failure while storing keys");
 
             ResultSet resultSet = cassandra.getConf().execute(select()
                     .from(MailRepositoryTable.CONTENT_TABLE_NAME));


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


[09/12] james-project git commit: JAMES-2630 Migrate CassandraAsyncExecutor.executeReturnApplied consumers to Reactor

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
----------------------------------------------------------------------
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 23297ee..dab5496 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
@@ -46,7 +46,6 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
-import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -76,8 +75,6 @@ import org.apache.james.mailbox.store.mail.MessageMapper.FetchType;
 import org.apache.james.mailbox.store.mail.model.MailboxMessage;
 import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleProperty;
-import org.apache.james.util.CompletableFutureUtil;
-import org.apache.james.util.FluentFutureStream;
 import org.apache.james.util.streams.JamesCollectors;
 import org.apache.james.util.streams.Limit;
 
@@ -95,6 +92,8 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.primitives.Bytes;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraMessageDAO {
     public static final long DEFAULT_LONG_VALUE = 0L;
@@ -234,42 +233,36 @@ public class CassandraMessageDAO {
             .collect(Guavate.toImmutableList());
     }
 
-    public CompletableFuture<Stream<MessageResult>> retrieveMessages(List<ComposedMessageIdWithMetaData> messageIds, FetchType fetchType, Limit limit) {
-        return CompletableFutureUtil.chainAll(
-                limit.applyOnStream(messageIds.stream().distinct())
-                    .collect(JamesCollectors.chunker(configuration.getMessageReadChunkSize())),
-            ids -> rowToMessages(fetchType, ids))
-            .thenApply(stream -> stream.flatMap(Function.identity()));
+    public Flux<MessageResult> retrieveMessages(List<ComposedMessageIdWithMetaData> messageIds, FetchType fetchType, Limit limit) {
+        return Flux.fromStream(limit.applyOnStream(messageIds.stream().distinct())
+            .collect(JamesCollectors.chunker(configuration.getMessageReadChunkSize())))
+            .flatMap(ids -> rowToMessages(fetchType, ids));
     }
 
-    private CompletableFuture<Stream<MessageResult>> rowToMessages(FetchType fetchType, Collection<ComposedMessageIdWithMetaData> ids) {
-        return FluentFutureStream.of(
-            ids.stream()
-                .map(id -> retrieveRow(id, fetchType)
-                    .thenCompose((ResultSet resultSet) -> message(resultSet, id, fetchType))))
-            .completableFuture();
+    private Flux<MessageResult> rowToMessages(FetchType fetchType, Collection<ComposedMessageIdWithMetaData> ids) {
+        return Flux.fromIterable(ids)
+            .flatMap(id -> retrieveRow(id, fetchType)
+                .flatMap(resultSet -> message(resultSet, id, fetchType)));
     }
 
-    private CompletableFuture<ResultSet> retrieveRow(ComposedMessageIdWithMetaData messageId, FetchType fetchType) {
+    private Mono<ResultSet> retrieveRow(ComposedMessageIdWithMetaData messageId, FetchType fetchType) {
         CassandraMessageId cassandraMessageId = (CassandraMessageId) messageId.getComposedMessageId().getMessageId();
 
-        return cassandraAsyncExecutor.execute(retrieveSelect(fetchType)
+        return cassandraAsyncExecutor.executeReactor(retrieveSelect(fetchType)
             .bind()
             .setUUID(MESSAGE_ID, cassandraMessageId.get()));
     }
 
-    private CompletableFuture<MessageResult>
+    private Mono<MessageResult>
     message(ResultSet rows,ComposedMessageIdWithMetaData messageIdWithMetaData, FetchType fetchType) {
         ComposedMessageId messageId = messageIdWithMetaData.getComposedMessageId();
 
         if (rows.isExhausted()) {
-            return CompletableFuture.completedFuture(notFound(messageIdWithMetaData));
+            return Mono.just(notFound(messageIdWithMetaData));
         }
 
         Row row = rows.one();
-        CompletableFuture<byte[]> contentFuture = buildContentRetriever(fetchType).apply(row);
-
-        return contentFuture.thenApply(content -> {
+        return buildContentRetriever(fetchType, row).map(content -> {
             MessageWithoutAttachment messageWithoutAttachment =
                 new MessageWithoutAttachment(
                     messageId.getMessageId(),
@@ -341,37 +334,37 @@ public class CassandraMessageDAO {
             .setUUID(MESSAGE_ID, messageId.get()));
     }
 
-    private Function<Row, CompletableFuture<byte[]>> buildContentRetriever(FetchType fetchType) {
+    private Mono<byte[]> buildContentRetriever(FetchType fetchType, Row row) {
         switch (fetchType) {
             case Full:
-                return this::getFullContent;
+                return getFullContent(row);
             case Headers:
-                return this::getHeaderContent;
+                return getHeaderContent(row);
             case Body:
-                return row -> getBodyContent(row)
-                    .thenApply(data -> Bytes.concat(new byte[row.getInt(BODY_START_OCTET)], data));
+                return getBodyContent(row)
+                    .map(data -> Bytes.concat(new byte[row.getInt(BODY_START_OCTET)], data));
             case Metadata:
-                return row -> CompletableFuture.completedFuture(EMPTY_BYTE_ARRAY);
+                return Mono.just(EMPTY_BYTE_ARRAY);
             default:
                 throw new RuntimeException("Unknown FetchType " + fetchType);
         }
     }
 
-    private CompletableFuture<byte[]> getFullContent(Row row) {
+    private Mono<byte[]> getFullContent(Row row) {
         return getHeaderContent(row)
-            .thenCombine(getBodyContent(row), Bytes::concat);
+            .zipWith(getBodyContent(row), Bytes::concat);
     }
 
-    private CompletableFuture<byte[]> getBodyContent(Row row) {
+    private Mono<byte[]> getBodyContent(Row row) {
         return getFieldContent(BODY_CONTENT, row);
     }
 
-    private CompletableFuture<byte[]> getHeaderContent(Row row) {
+    private Mono<byte[]> getHeaderContent(Row row) {
         return getFieldContent(HEADER_CONTENT, row);
     }
 
-    private CompletableFuture<byte[]> getFieldContent(String field, Row row) {
-        return blobStore.readBytes(blobIdFactory.from(row.getString(field)));
+    private Mono<byte[]> getFieldContent(String field, Row row) {
+        return Mono.fromFuture(blobStore.readBytes(blobIdFactory.from(row.getString(field))));
     }
 
     public static MessageResult notFound(ComposedMessageIdWithMetaData id) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
index 51365e6..fe93143 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
@@ -67,6 +67,7 @@ import com.datastax.driver.core.Session;
 import com.datastax.driver.core.querybuilder.QueryBuilder;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableSet;
+import reactor.core.publisher.Mono;
 
 public class CassandraMessageIdDAO {
 
@@ -169,8 +170,8 @@ public class CassandraMessageIdDAO {
                 .and(lte(IMAP_UID, bindMarker(IMAP_UID_LTE))));
     }
 
-    public CompletableFuture<Void> delete(CassandraId mailboxId, MessageUid uid) {
-        return cassandraAsyncExecutor.executeVoid(delete.bind()
+    public Mono<Void> delete(CassandraId mailboxId, MessageUid uid) {
+        return cassandraAsyncExecutor.executeVoidReactor(delete.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid())
                 .setLong(IMAP_UID, uid.asLong()));
     }
@@ -193,10 +194,10 @@ public class CassandraMessageIdDAO {
                 .setSet(USER_FLAGS, ImmutableSet.copyOf(flags.getUserFlags())));
     }
 
-    public CompletableFuture<Void> updateMetadata(ComposedMessageIdWithMetaData composedMessageIdWithMetaData) {
+    public Mono<Void> updateMetadata(ComposedMessageIdWithMetaData composedMessageIdWithMetaData) {
         ComposedMessageId composedMessageId = composedMessageIdWithMetaData.getComposedMessageId();
         Flags flags = composedMessageIdWithMetaData.getFlags();
-        return cassandraAsyncExecutor.executeVoid(update.bind()
+        return cassandraAsyncExecutor.executeVoidReactor(update.bind()
                 .setLong(MOD_SEQ, composedMessageIdWithMetaData.getModSeq())
                 .setBool(ANSWERED, flags.contains(Flag.ANSWERED))
                 .setBool(DELETED, flags.contains(Flag.DELETED))

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
----------------------------------------------------------------------
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 880ac16..0a7c0bc 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
@@ -24,14 +24,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
 import java.util.stream.Stream;
 
 import javax.mail.Flags;
 
 import org.apache.commons.lang3.tuple.Pair;
+
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
-import org.apache.james.backends.cassandra.utils.FunctionRunnerWithRetry;
-import org.apache.james.backends.cassandra.utils.LightweightTransactionException;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
@@ -49,7 +49,8 @@ import org.apache.james.mailbox.store.mail.MessageMapper.FetchType;
 import org.apache.james.mailbox.store.mail.ModSeqProvider;
 import org.apache.james.mailbox.store.mail.model.MailboxMessage;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
-import org.apache.james.util.FluentFutureStream;
+import org.apache.james.util.FunctionalUtils;
+import org.apache.james.util.ReactorUtils;
 import org.apache.james.util.streams.JamesCollectors;
 import org.apache.james.util.streams.Limit;
 import org.slf4j.Logger;
@@ -57,6 +58,7 @@ import org.slf4j.LoggerFactory;
 
 import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.Multimap;
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraMessageIdMapper implements MessageIdMapper {
@@ -99,47 +101,37 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
     }
 
     private Stream<SimpleMailboxMessage> findAsStream(Collection<MessageId> messageIds, FetchType fetchType) {
-        return FluentFutureStream.of(
-                messageIds.stream()
-                    .map(messageId -> imapUidDAO.retrieve((CassandraMessageId) messageId, Optional.empty())),
-                FluentFutureStream::unboxStream)
-            .collect(Guavate.toImmutableList())
-            .thenCompose(composedMessageIds -> messageDAO.retrieveMessages(composedMessageIds, fetchType, Limit.unlimited()))
-            .thenApply(stream -> stream
+        return Flux.fromStream(messageIds.stream())
+                .flatMap(messageId -> imapUidDAO.retrieve((CassandraMessageId) messageId, Optional.empty()))
+                .collectList()
+                .flatMapMany(composedMessageIds -> messageDAO.retrieveMessages(composedMessageIds, fetchType, Limit.unlimited()))
                 .filter(CassandraMessageDAO.MessageResult::isFound)
-                .map(CassandraMessageDAO.MessageResult::message))
-            .thenCompose(stream -> attachmentLoader.addAttachmentToMessages(stream, fetchType))
-            .thenCompose(this::filterMessagesWithExistingMailbox)
-            .join()
-            .sorted(Comparator.comparing(MailboxMessage::getUid));
-    }
-
-    private CompletableFuture<Stream<SimpleMailboxMessage>> filterMessagesWithExistingMailbox(Stream<SimpleMailboxMessage> stream) {
-        return FluentFutureStream.of(stream.map(this::keepMessageIfMailboxExists), FluentFutureStream::unboxOptional)
-            .completableFuture();
+                .map(CassandraMessageDAO.MessageResult::message)
+                .flatMap(messageRepresentation -> attachmentLoader.addAttachmentToMessage(messageRepresentation, fetchType))
+                .flatMap(this::keepMessageIfMailboxExists)
+                .collectSortedList(Comparator.comparing(MailboxMessage::getUid))
+                .block()
+                .stream();
     }
 
-    private CompletableFuture<Optional<SimpleMailboxMessage>> keepMessageIfMailboxExists(SimpleMailboxMessage message) {
+    private Mono<SimpleMailboxMessage> keepMessageIfMailboxExists(SimpleMailboxMessage message) {
         CassandraId cassandraId = (CassandraId) message.getMailboxId();
         return mailboxDAO.retrieveMailbox(cassandraId)
-            .thenApply(optional -> {
-                if (!optional.isPresent()) {
+            .map(any -> message)
+            .switchIfEmpty(ReactorUtils.executeAndEmpty(() -> {
                     LOGGER.info("Mailbox {} have been deleted but message {} is still attached to it.",
                         cassandraId,
                         message.getMailboxId());
-                    return Optional.empty();
-                }
-
-                return Optional.of(message);
-            });
+                }));
     }
 
     @Override
     public List<MailboxId> findMailboxes(MessageId messageId) {
-        return imapUidDAO.retrieve((CassandraMessageId) messageId, Optional.empty()).join()
+        return imapUidDAO.retrieve((CassandraMessageId) messageId, Optional.empty())
             .map(ComposedMessageIdWithMetaData::getComposedMessageId)
             .map(ComposedMessageId::getMailboxId)
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
     }
 
     @Override
@@ -182,114 +174,115 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
 
     @Override
     public void delete(MessageId messageId, Collection<MailboxId> mailboxIds) {
-        deleteAsFuture(messageId, mailboxIds).join();
+        deleteAsMono(messageId, mailboxIds).block();
     }
 
-    public CompletableFuture<Void> deleteAsFuture(MessageId messageId, Collection<MailboxId> mailboxIds) {
+    public Mono<Void> deleteAsMono(MessageId messageId, Collection<MailboxId> mailboxIds) {
         CassandraMessageId cassandraMessageId = (CassandraMessageId) messageId;
-        return mailboxIds.stream()
-            .map(mailboxId -> retrieveAndDeleteIndices(cassandraMessageId, Optional.of((CassandraId) mailboxId)))
-            .reduce((f1, f2) -> CompletableFuture.allOf(f1, f2))
-            .orElse(CompletableFuture.completedFuture(null));
+        return Flux.fromStream(mailboxIds.stream())
+            .flatMap(mailboxId -> retrieveAndDeleteIndices(cassandraMessageId, Optional.of((CassandraId) mailboxId)))
+            .then();
     }
 
     @Override
     public void delete(Multimap<MessageId, MailboxId> ids) {
-        ids.asMap()
-            .entrySet()
-            .stream()
-            .collect(JamesCollectors.chunker(cassandraConfiguration.getExpungeChunkSize()))
-            .forEach(chunk ->
-                FluentFutureStream.of(chunk.stream()
-                    .map(entry -> deleteAsFuture(entry.getKey(), entry.getValue())))
-                    .join());
+        Flux.fromIterable(ids.asMap()
+            .entrySet())
+            .limitRate(cassandraConfiguration.getExpungeChunkSize())
+            .flatMap(entry -> deleteAsMono(entry.getKey(), entry.getValue()))
+            .then()
+            .block();
     }
 
-    private CompletableFuture<Void> retrieveAndDeleteIndices(CassandraMessageId messageId, Optional<CassandraId> mailboxId) {
+    private Mono<Void> retrieveAndDeleteIndices(CassandraMessageId messageId, Optional<CassandraId> mailboxId) {
         return imapUidDAO.retrieve(messageId, mailboxId)
-            .thenCompose(composedMessageIds -> composedMessageIds
-                .map(this::deleteIds)
-                .reduce((f1, f2) -> CompletableFuture.allOf(f1, f2))
-                .orElse(CompletableFuture.completedFuture(null)));
+            .flatMap(this::deleteIds)
+            .then();
     }
 
     @Override
     public void delete(MessageId messageId) {
         CassandraMessageId cassandraMessageId = (CassandraMessageId) messageId;
         retrieveAndDeleteIndices(cassandraMessageId, Optional.empty())
-            .join();
+            .block();
     }
 
-    private CompletableFuture<Void> deleteIds(ComposedMessageIdWithMetaData metaData) {
+    private Mono<Void> deleteIds(ComposedMessageIdWithMetaData metaData) {
         CassandraMessageId messageId = (CassandraMessageId) metaData.getComposedMessageId().getMessageId();
         CassandraId mailboxId = (CassandraId) metaData.getComposedMessageId().getMailboxId();
-        return CompletableFuture.allOf(
-            imapUidDAO.delete(messageId, mailboxId),
-            messageIdDAO.delete(mailboxId, metaData.getComposedMessageId().getUid()))
-            .thenCompose(voidValue -> indexTableHandler.updateIndexOnDelete(metaData, mailboxId).toFuture());
+        return Flux.merge(
+                imapUidDAO.delete(messageId, mailboxId),
+                messageIdDAO.delete(mailboxId, metaData.getComposedMessageId().getUid()))
+            .then(indexTableHandler.updateIndexOnDelete(metaData, mailboxId));
     }
 
     @Override
     public Map<MailboxId, UpdatedFlags> setFlags(MessageId messageId, List<MailboxId> mailboxIds, Flags newState, MessageManager.FlagsUpdateMode updateMode) throws MailboxException {
-        return mailboxIds.stream()
+        return Flux.fromIterable(mailboxIds)
             .distinct()
             .map(mailboxId -> (CassandraId) mailboxId)
-            .filter(mailboxId -> imapUidDAO.retrieve((CassandraMessageId) messageId, Optional.of(mailboxId))
-                .join()
-                .findAny()
-                .isPresent())
+            .filter(mailboxId -> haveMetaData(messageId, mailboxId))
             .flatMap(mailboxId -> flagsUpdateWithRetry(newState, updateMode, mailboxId, messageId))
-            .map(this::updateCounts)
-            .map(Mono::block)
-            .collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight));
+            .flatMap(this::updateCounts)
+            .collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight))
+            .block();
     }
 
-    private Stream<Pair<MailboxId, UpdatedFlags>> flagsUpdateWithRetry(Flags newState, MessageManager.FlagsUpdateMode updateMode, MailboxId mailboxId, MessageId messageId) {
+    private boolean haveMetaData(MessageId messageId, CassandraId mailboxId) {
+        return imapUidDAO.retrieve((CassandraMessageId) messageId, Optional.of(mailboxId))
+            .hasElements()
+            .block();
+    }
+
+    private Mono<Pair<MailboxId, UpdatedFlags>> flagsUpdateWithRetry(Flags newState, MessageManager.FlagsUpdateMode updateMode, MailboxId mailboxId, MessageId messageId) {
         try {
-            Pair<Flags, ComposedMessageIdWithMetaData> pair = new FunctionRunnerWithRetry(cassandraConfiguration.getFlagsUpdateMessageIdMaxRetry())
-                .executeAndRetrieveObject(() -> tryFlagsUpdate(newState, updateMode, mailboxId, messageId));
-            ComposedMessageIdWithMetaData composedMessageIdWithMetaData = pair.getRight();
-            Flags oldFlags = pair.getLeft();
-            return Stream.of(Pair.of(composedMessageIdWithMetaData.getComposedMessageId().getMailboxId(),
-                    UpdatedFlags.builder()
-                        .uid(composedMessageIdWithMetaData.getComposedMessageId().getUid())
-                        .modSeq(composedMessageIdWithMetaData.getModSeq())
-                        .oldFlags(oldFlags)
-                        .newFlags(composedMessageIdWithMetaData.getFlags())
-                        .build()));
-        } catch (LightweightTransactionException e) {
-            throw new RuntimeException(e);
+            return Mono.defer(() -> tryFlagsUpdate(newState, updateMode, mailboxId, messageId))
+                .single()
+                .retry(cassandraConfiguration.getFlagsUpdateMessageIdMaxRetry())
+                .map(pair -> buildUpdatedFlags(pair.getRight(), pair.getLeft()));
         } catch (MailboxDeleteDuringUpdateException e) {
             LOGGER.info("Mailbox {} was deleted during flag update", mailboxId);
-            return Stream.of();
+            return Mono.empty();
         }
     }
 
+    private Pair<MailboxId, UpdatedFlags> buildUpdatedFlags(ComposedMessageIdWithMetaData composedMessageIdWithMetaData, Flags oldFlags) {
+        return Pair.of(composedMessageIdWithMetaData.getComposedMessageId().getMailboxId(),
+                UpdatedFlags.builder()
+                    .uid(composedMessageIdWithMetaData.getComposedMessageId().getUid())
+                    .modSeq(composedMessageIdWithMetaData.getModSeq())
+                    .oldFlags(oldFlags)
+                    .newFlags(composedMessageIdWithMetaData.getFlags())
+                    .build());
+    }
+
     private Mono<Pair<MailboxId, UpdatedFlags>> updateCounts(Pair<MailboxId, UpdatedFlags> pair) {
         CassandraId cassandraId = (CassandraId) pair.getLeft();
         return indexTableHandler.updateIndexOnFlagsUpdate(cassandraId, pair.getRight())
-            .then(Mono.just(pair));
+            .thenReturn(pair);
     }
 
-    private Optional<Pair<Flags, ComposedMessageIdWithMetaData>> tryFlagsUpdate(Flags newState, MessageManager.FlagsUpdateMode updateMode, MailboxId mailboxId, MessageId messageId) {
+    private Mono<Pair<Flags, ComposedMessageIdWithMetaData>> tryFlagsUpdate(Flags newState, MessageManager.FlagsUpdateMode updateMode, MailboxId mailboxId, MessageId messageId) {
         try {
             return updateFlags(mailboxId, messageId, newState, updateMode);
         } catch (MailboxException e) {
             LOGGER.error("Error while updating flags on mailbox: {}", mailboxId);
-            return Optional.empty();
+            return Mono.empty();
         }
     }
 
-    private Optional<Pair<Flags, ComposedMessageIdWithMetaData>> updateFlags(MailboxId mailboxId, MessageId messageId, Flags newState, MessageManager.FlagsUpdateMode updateMode) throws MailboxException {
+    private Mono<Pair<Flags, ComposedMessageIdWithMetaData>> updateFlags(MailboxId mailboxId, MessageId messageId, Flags newState, MessageManager.FlagsUpdateMode updateMode) throws MailboxException {
         CassandraId cassandraId = (CassandraId) mailboxId;
         ComposedMessageIdWithMetaData oldComposedId = imapUidDAO.retrieve((CassandraMessageId) messageId, Optional.of(cassandraId))
-            .join()
-            .findFirst()
+            .next()
+            .blockOptional()
             .orElseThrow(MailboxDeleteDuringUpdateException::new);
+
         Flags newFlags = new FlagsUpdateCalculator(newState, updateMode).buildNewFlags(oldComposedId.getFlags());
         if (identicalFlags(oldComposedId, newFlags)) {
-            return Optional.of(Pair.of(oldComposedId.getFlags(), oldComposedId));
+            return Mono.just(Pair.of(oldComposedId.getFlags(), oldComposedId));
         }
+
         ComposedMessageIdWithMetaData newComposedId = new ComposedMessageIdWithMetaData(
             oldComposedId.getComposedMessageId(),
             newFlags,
@@ -302,15 +295,10 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
         return oldComposedId.getFlags().equals(newFlags);
     }
 
-    private Optional<Pair<Flags, ComposedMessageIdWithMetaData>> updateFlags(ComposedMessageIdWithMetaData oldComposedId, ComposedMessageIdWithMetaData newComposedId) {
+    private Mono<Pair<Flags, ComposedMessageIdWithMetaData>> updateFlags(ComposedMessageIdWithMetaData oldComposedId, ComposedMessageIdWithMetaData newComposedId) {
         return imapUidDAO.updateMetadata(newComposedId, oldComposedId.getModSeq())
-            .thenCompose(updateSuccess -> Optional.of(updateSuccess)
-                .filter(b -> b)
-                .map((Boolean any) -> messageIdDAO.updateMetadata(newComposedId).thenApply(v -> updateSuccess))
-                .orElse(CompletableFuture.completedFuture(updateSuccess)))
-            .thenApply(success -> Optional.of(success)
-                .filter(b -> b)
-                .map(any -> Pair.of(oldComposedId.getFlags(), newComposedId)))
-            .join();
+            .filter(FunctionalUtils.toPredicate(Function.identity()))
+            .flatMap(any -> messageIdDAO.updateMetadata(newComposedId)
+                .thenReturn(Pair.of(oldComposedId.getFlags(), newComposedId)));
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
index 169e32d..be5686a 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
@@ -42,7 +42,6 @@ import static org.apache.james.mailbox.cassandra.table.MessageIdToImapUid.TABLE_
 
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
 
 import javax.inject.Inject;
 import javax.mail.Flags;
@@ -64,6 +63,8 @@ import com.datastax.driver.core.Session;
 import com.datastax.driver.core.querybuilder.QueryBuilder;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableSet;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraMessageIdToImapUidDAO {
 
@@ -148,8 +149,8 @@ public class CassandraMessageIdToImapUidDAO {
                 .and(eq(MAILBOX_ID, bindMarker(MAILBOX_ID))));
     }
 
-    public CompletableFuture<Void> delete(CassandraMessageId messageId, CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeVoid(delete.bind()
+    public Mono<Void> delete(CassandraMessageId messageId, CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeVoidReactor(delete.bind()
                 .setUUID(MESSAGE_ID, messageId.get())
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()));
     }
@@ -172,7 +173,7 @@ public class CassandraMessageIdToImapUidDAO {
                 .setSet(USER_FLAGS, ImmutableSet.copyOf(flags.getUserFlags())));
     }
 
-    public CompletableFuture<Boolean> updateMetadata(ComposedMessageIdWithMetaData composedMessageIdWithMetaData, long oldModSeq) {
+    public Mono<Boolean> updateMetadata(ComposedMessageIdWithMetaData composedMessageIdWithMetaData, long oldModSeq) {
         ComposedMessageId composedMessageId = composedMessageIdWithMetaData.getComposedMessageId();
         Flags flags = composedMessageIdWithMetaData.getFlags();
         return cassandraAsyncExecutor.executeReturnApplied(update.bind()
@@ -191,10 +192,10 @@ public class CassandraMessageIdToImapUidDAO {
                 .setLong(MOD_SEQ_CONDITION, oldModSeq));
     }
 
-    public CompletableFuture<Stream<ComposedMessageIdWithMetaData>> retrieve(CassandraMessageId messageId, Optional<CassandraId> mailboxId) {
+    public Flux<ComposedMessageIdWithMetaData> retrieve(CassandraMessageId messageId, Optional<CassandraId> mailboxId) {
         return selectStatement(messageId, mailboxId)
-                .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet)
-                        .map(this::toComposedMessageIdWithMetadata));
+                .flatMapMany(cassandraUtils::convertToFlux)
+                .map(this::toComposedMessageIdWithMetadata);
     }
 
     private ComposedMessageIdWithMetaData toComposedMessageIdWithMetadata(Row row) {
@@ -208,12 +209,12 @@ public class CassandraMessageIdToImapUidDAO {
                 .build();
     }
 
-    private CompletableFuture<ResultSet> selectStatement(CassandraMessageId messageId, Optional<CassandraId> mailboxId) {
+    private Mono<ResultSet> selectStatement(CassandraMessageId messageId, Optional<CassandraId> mailboxId) {
         return mailboxId
-            .map(cassandraId -> cassandraAsyncExecutor.execute(select.bind()
+            .map(cassandraId -> cassandraAsyncExecutor.executeReactor(select.bind()
                 .setUUID(MESSAGE_ID, messageId.get())
                 .setUUID(MAILBOX_ID, cassandraId.asUuid())))
-            .orElseGet(() -> cassandraAsyncExecutor.execute(selectAll.bind()
+            .orElseGet(() -> cassandraAsyncExecutor.executeReactor(selectAll.bind()
                 .setUUID(MESSAGE_ID, messageId.get())));
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
----------------------------------------------------------------------
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 f2b468f..d2c4006 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
@@ -24,7 +24,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
 
 import javax.mail.Flags;
 import javax.mail.Flags.Flag;
@@ -50,6 +50,7 @@ import org.apache.james.mailbox.store.mail.model.Mailbox;
 import org.apache.james.mailbox.store.mail.model.MailboxMessage;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
 import org.apache.james.util.OptionalUtils;
+import org.apache.james.util.ReactorUtils;
 import org.apache.james.util.streams.Limit;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -153,8 +154,8 @@ public class CassandraMessageMapper implements MessageMapper {
         CassandraId mailboxId = (CassandraId) composedMessageId.getMailboxId();
         MessageUid uid = composedMessageId.getUid();
         return Flux.merge(
-                Mono.fromCompletionStage(imapUidDAO.delete(messageId, mailboxId)),
-                Mono.fromCompletionStage(messageIdDAO.delete(mailboxId, uid)))
+                imapUidDAO.delete(messageId, mailboxId),
+                messageIdDAO.delete(mailboxId, uid))
             .then(indexTableHandler.updateIndexOnDelete(composedMessageIdWithMetaData, mailboxId));
     }
 
@@ -162,9 +163,9 @@ public class CassandraMessageMapper implements MessageMapper {
     public Iterator<MailboxMessage> findInMailbox(Mailbox mailbox, MessageRange messageRange, FetchType ftype, int max) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
         return retrieveMessages(retrieveMessageIds(mailboxId, messageRange), ftype, Limit.from(max))
-            .map(SimpleMailboxMessage -> (MailboxMessage) SimpleMailboxMessage)
+            .map(simpleMailboxMessage -> (MailboxMessage) simpleMailboxMessage)
             .collectSortedList(Comparator.comparing(MailboxMessage::getUid))
-            .flatMapMany(Flux::fromIterable)
+            .flatMapIterable(Function.identity())
             .toIterable()
             .iterator();
     }
@@ -176,12 +177,10 @@ public class CassandraMessageMapper implements MessageMapper {
     }
 
     private Flux<SimpleMailboxMessage> retrieveMessages(List<ComposedMessageIdWithMetaData> messageIds, FetchType fetchType, Limit limit) {
-        return Mono.fromCompletionStage(messageDAO.retrieveMessages(messageIds, fetchType, limit))
-            .map(stream -> stream
-                .filter(CassandraMessageDAO.MessageResult::isFound)
-                .map(CassandraMessageDAO.MessageResult::message))
-            .flatMap(stream -> Mono.fromCompletionStage(attachmentLoader.addAttachmentToMessages(stream, fetchType)))
-            .flatMapMany(Flux::fromStream);
+        return messageDAO.retrieveMessages(messageIds, fetchType, limit)
+            .filter(CassandraMessageDAO.MessageResult::isFound)
+            .map(CassandraMessageDAO.MessageResult::message)
+            .flatMap(stream -> attachmentLoader.addAttachmentToMessage(stream, fetchType));
     }
 
     @Override
@@ -196,9 +195,7 @@ public class CassandraMessageMapper implements MessageMapper {
     public MessageUid findFirstUnseenMessageUid(Mailbox mailbox) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
         return firstUnseenDAO.retrieveFirstUnread(mailboxId)
-                .map(Optional::of)
-                .defaultIfEmpty(Optional.empty())
-                .block()
+                .blockOptional()
                 .orElse(null);
     }
 
@@ -216,9 +213,8 @@ public class CassandraMessageMapper implements MessageMapper {
     private Flux<SimpleMailboxMessage> expungeOne(CassandraId mailboxId, MessageUid messageUid) {
         return retrieveComposedId(mailboxId, messageUid)
             .flatMap(idWithMetadata -> deleteUsingMailboxId(idWithMetadata).thenReturn(idWithMetadata))
-            .flatMap(idWithMetadata ->
-                Mono.fromCompletionStage(messageDAO.retrieveMessages(ImmutableList.of(idWithMetadata), FetchType.Metadata, Limit.unlimited())))
-            .flatMapMany(Flux::fromStream)
+            .flatMapMany(idWithMetadata ->
+                messageDAO.retrieveMessages(ImmutableList.of(idWithMetadata), FetchType.Metadata, Limit.unlimited()))
             .filter(CassandraMessageDAO.MessageResult::isFound)
             .map(CassandraMessageDAO.MessageResult::message)
             .map(pair -> pair.getKey().toMailboxMessage(ImmutableList.of()));
@@ -262,13 +258,13 @@ public class CassandraMessageMapper implements MessageMapper {
     }
 
     private MailboxMessage addUidAndModseq(MailboxMessage message, CassandraId mailboxId) throws MailboxException {
-        CompletableFuture<Optional<MessageUid>> uidFuture = uidProvider.nextUid(mailboxId);
-        CompletableFuture<Optional<Long>> modseqFuture = modSeqProvider.nextModSeq(mailboxId);
-        CompletableFuture.allOf(uidFuture, modseqFuture).join();
+        final Mono<MessageUid> messageUidMono = uidProvider.nextUid(mailboxId).cache();
+        final Mono<Long> nextModSeqMono = modSeqProvider.nextModSeq(mailboxId).cache();
+        Flux.merge(messageUidMono, nextModSeqMono).then();
 
-        message.setUid(uidFuture.join()
+        message.setUid(messageUidMono.blockOptional()
             .orElseThrow(() -> new MailboxException("Can not find a UID to save " + message.getMessageId() + " in " + mailboxId)));
-        message.setModSeq(modseqFuture.join()
+        message.setModSeq(nextModSeqMono.blockOptional()
             .orElseThrow(() -> new MailboxException("Can not find a MODSEQ to save " + message.getMessageId() + " in " + mailboxId)));
 
         return message;
@@ -323,8 +319,8 @@ public class CassandraMessageMapper implements MessageMapper {
     }
 
     private Mono<Long> computeNewModSeq(CassandraId mailboxId) {
-        return Mono.fromCompletionStage(modSeqProvider.nextModSeq(mailboxId))
-            .map(value -> value.orElseThrow(() -> new RuntimeException("ModSeq generation failed for mailbox " + mailboxId.asUuid())));
+        return modSeqProvider.nextModSeq(mailboxId)
+            .switchIfEmpty(ReactorUtils.executeAndEmpty(() -> new RuntimeException("ModSeq generation failed for mailbox " + mailboxId.asUuid())));
     }
 
     private Mono<FlagsUpdateStageResult> updateIndexesForUpdatesResult(CassandraId mailboxId, FlagsUpdateStageResult result) {
@@ -429,11 +425,10 @@ public class CassandraMessageMapper implements MessageMapper {
                 .modSeq(newModSeq)
                 .flags(newFlags)
                 .build();
-        return Mono.fromCompletionStage(imapUidDAO.updateMetadata(newMetadata, oldMetadata.getModSeq()))
+        return imapUidDAO.updateMetadata(newMetadata, oldMetadata.getModSeq())
             .flatMap(success -> {
                 if (success) {
-                    return Mono.fromCompletionStage(messageIdDAO.updateMetadata(newMetadata))
-                        .then(Mono.just(true));
+                    return messageIdDAO.updateMetadata(newMetadata).thenReturn(true);
                 } else {
                     return Mono.just(false);
                 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java
index 63e045b..6f798c5 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProvider.java
@@ -29,30 +29,33 @@ import static org.apache.james.mailbox.cassandra.table.CassandraMessageModseqTab
 import static org.apache.james.mailbox.cassandra.table.CassandraMessageModseqTable.NEXT_MODSEQ;
 import static org.apache.james.mailbox.cassandra.table.CassandraMessageModseqTable.TABLE_NAME;
 
+import java.time.Duration;
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionException;
+import java.util.function.Function;
 import java.util.function.Supplier;
 
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.backends.cassandra.utils.FunctionRunnerWithRetry;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.store.mail.ModSeqProvider;
 import org.apache.james.mailbox.store.mail.model.Mailbox;
+import org.apache.james.util.FunctionalUtils;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
-import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
+import reactor.core.publisher.Mono;
 
 public class CassandraModSeqProvider implements ModSeqProvider {
 
     public static final String MOD_SEQ_CONDITION = "modSeqCondition";
+    private final long maxModSeqRetries;
 
     public static class ExceptionRelay extends RuntimeException {
         private final MailboxException underlying;
@@ -81,7 +84,6 @@ public class CassandraModSeqProvider implements ModSeqProvider {
     private static final ModSeq FIRST_MODSEQ = new ModSeq(0);
 
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
-    private final FunctionRunnerWithRetry runner;
     private final PreparedStatement select;
     private final PreparedStatement update;
     private final PreparedStatement insert;
@@ -89,17 +91,12 @@ public class CassandraModSeqProvider implements ModSeqProvider {
     @Inject
     public CassandraModSeqProvider(Session session, CassandraConfiguration cassandraConfiguration) {
         this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
-        this.runner = new FunctionRunnerWithRetry(cassandraConfiguration.getModSeqMaxRetry());
+        this.maxModSeqRetries = cassandraConfiguration.getModSeqMaxRetry();
         this.insert = prepareInsert(session);
         this.update = prepareUpdate(session);
         this.select = prepareSelect(session);
     }
 
-    @VisibleForTesting
-    public CassandraModSeqProvider(Session session) {
-        this(session, CassandraConfiguration.DEFAULT_CONFIGURATION);
-    }
-
     private PreparedStatement prepareInsert(Session session) {
         return session.prepare(insertInto(TABLE_NAME)
             .value(NEXT_MODSEQ, bindMarker(NEXT_MODSEQ))
@@ -125,81 +122,79 @@ public class CassandraModSeqProvider implements ModSeqProvider {
     @Override
     public long nextModSeq(MailboxSession mailboxSession, Mailbox mailbox) throws MailboxException {
         CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
-        return nextModSeq(mailboxId).join()
+        return nextModSeq(mailboxId)
+            .blockOptional()
             .orElseThrow(() -> new MailboxException("Can not retrieve modseq for " + mailboxId));
     }
 
     @Override
     public long nextModSeq(MailboxSession session, MailboxId mailboxId) throws MailboxException {
         return nextModSeq((CassandraId) mailboxId)
-            .join()
+            .blockOptional()
             .orElseThrow(() -> new MailboxException("Can not retrieve modseq for " + mailboxId));
     }
 
     @Override
     public long highestModSeq(MailboxSession mailboxSession, Mailbox mailbox) throws MailboxException {
-        return unbox(() -> findHighestModSeq((CassandraId) mailbox.getMailboxId()).join().getValue());
+        return highestModSeq(mailboxSession, mailbox.getMailboxId());
     }
 
     @Override
     public long highestModSeq(MailboxSession mailboxSession, MailboxId mailboxId) throws MailboxException {
-        return unbox(() -> findHighestModSeq((CassandraId) mailboxId).join().getValue());
+        return unbox(() -> findHighestModSeq((CassandraId) mailboxId).block().orElse(FIRST_MODSEQ).getValue());
     }
 
-    private CompletableFuture<ModSeq> findHighestModSeq(CassandraId mailboxId) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    private Mono<Optional<ModSeq>> findHighestModSeq(CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeSingleRowOptionalReactor(
             select.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()))
-            .thenApply(optional -> optional.map(row -> new ModSeq(row.getLong(NEXT_MODSEQ)))
-                .orElse(FIRST_MODSEQ));
+            .map(maybeRow -> maybeRow.map(row -> new ModSeq(row.getLong(NEXT_MODSEQ))));
     }
 
-    private CompletableFuture<Optional<ModSeq>> tryInsertModSeq(CassandraId mailboxId, ModSeq modSeq) {
+    private Mono<ModSeq> tryInsertModSeq(CassandraId mailboxId, ModSeq modSeq) {
         ModSeq nextModSeq = modSeq.next();
         return cassandraAsyncExecutor.executeReturnApplied(
             insert.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid())
                 .setLong(NEXT_MODSEQ, nextModSeq.getValue()))
-            .thenApply(success -> successToModSeq(nextModSeq, success));
+            .flatMap(success -> successToModSeq(nextModSeq, success));
     }
 
-    private CompletableFuture<Optional<ModSeq>> tryUpdateModSeq(CassandraId mailboxId, ModSeq modSeq) {
+    private Mono<ModSeq> tryUpdateModSeq(CassandraId mailboxId, ModSeq modSeq) {
         ModSeq nextModSeq = modSeq.next();
         return cassandraAsyncExecutor.executeReturnApplied(
             update.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid())
                 .setLong(NEXT_MODSEQ, nextModSeq.getValue())
                 .setLong(MOD_SEQ_CONDITION, modSeq.getValue()))
-            .thenApply(success -> successToModSeq(nextModSeq, success));
+            .flatMap(success -> successToModSeq(nextModSeq, success));
     }
 
-    private Optional<ModSeq> successToModSeq(ModSeq modSeq, Boolean success) {
-        if (success) {
-            return Optional.of(modSeq);
-        }
-        return Optional.empty();
+    private Mono<ModSeq> successToModSeq(ModSeq modSeq, Boolean success) {
+        return Mono.just(success)
+            .filter(FunctionalUtils.toPredicate(Function.identity()))
+            .map(any -> modSeq);
     }
-    
-    public CompletableFuture<Optional<Long>> nextModSeq(CassandraId mailboxId) {
+
+    public Mono<Long> nextModSeq(CassandraId mailboxId) {
         return findHighestModSeq(mailboxId)
-            .thenCompose(modSeq -> {
-                if (modSeq.isFirst()) {
-                    return tryInsertModSeq(mailboxId, FIRST_MODSEQ);
-                }
-                return tryUpdateModSeq(mailboxId, modSeq);
-            }).thenCompose(firstInsert -> {
-                    if (firstInsert.isPresent()) {
-                        return CompletableFuture.completedFuture(firstInsert);
-                    }
-                    return handleRetries(mailboxId);
-                })
-            .thenApply(optional -> optional.map(ModSeq::getValue));
-    }
-
-    private CompletableFuture<Optional<ModSeq>> handleRetries(CassandraId mailboxId) {
-        return runner.executeAsyncAndRetrieveObject(
-            () -> findHighestModSeq(mailboxId)
-                .thenCompose(newModSeq -> tryUpdateModSeq(mailboxId, newModSeq)));
+            .flatMap(maybeHighestModSeq -> maybeHighestModSeq
+                        .map(highestModSeq -> tryUpdateModSeq(mailboxId, highestModSeq))
+                        .orElseGet(() -> tryInsertModSeq(mailboxId, FIRST_MODSEQ)))
+            .switchIfEmpty(handleRetries(mailboxId))
+            .map(ModSeq::getValue);
+    }
+
+    private Mono<ModSeq> handleRetries(CassandraId mailboxId) {
+        return tryFindThenUpdateOnce(mailboxId)
+            .single()
+            .retryBackoff(maxModSeqRetries, Duration.ofMillis(2));
+    }
+
+    private Mono<ModSeq> tryFindThenUpdateOnce(CassandraId mailboxId) {
+        return Mono.defer(() -> findHighestModSeq(mailboxId)
+            .flatMap(Mono::justOrEmpty)
+            .flatMap(highestModSeq -> tryUpdateModSeq(mailboxId, highestModSeq)));
     }
 
     private static class ModSeq {
@@ -216,9 +211,12 @@ public class CassandraModSeqProvider implements ModSeqProvider {
         public long getValue() {
             return value;
         }
-        
-        public boolean isFirst() {
-            return value == FIRST_MODSEQ.value;
+
+        @Override
+        public String toString() {
+            return MoreObjects.toStringHelper(this)
+                    .add("value", value)
+                    .toString();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java
index b402bf8..bd3baac 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java
@@ -30,13 +30,11 @@ import static org.apache.james.mailbox.cassandra.table.CassandraMessageUidTable.
 import static org.apache.james.mailbox.cassandra.table.CassandraMessageUidTable.TABLE_NAME;
 
 import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.backends.cassandra.utils.FunctionRunnerWithRetry;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
@@ -47,13 +45,13 @@ import org.apache.james.mailbox.store.mail.model.Mailbox;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
-import com.google.common.annotations.VisibleForTesting;
+import reactor.core.publisher.Mono;
 
 public class CassandraUidProvider implements UidProvider {
     private static final String CONDITION = "Condition";
 
     private final CassandraAsyncExecutor executor;
-    private final FunctionRunnerWithRetry runner;
+    private final long maxUidRetries;
     private final PreparedStatement insertStatement;
     private final PreparedStatement updateStatement;
     private final PreparedStatement selectStatement;
@@ -61,17 +59,12 @@ public class CassandraUidProvider implements UidProvider {
     @Inject
     public CassandraUidProvider(Session session, CassandraConfiguration cassandraConfiguration) {
         this.executor = new CassandraAsyncExecutor(session);
-        this.runner = new FunctionRunnerWithRetry(cassandraConfiguration.getUidMaxRetry());
+        this.maxUidRetries = cassandraConfiguration.getUidMaxRetry();
         this.selectStatement = prepareSelect(session);
         this.updateStatement = prepareUpdate(session);
         this.insertStatement = prepareInsert(session);
     }
 
-    @VisibleForTesting
-    public CassandraUidProvider(Session session) {
-        this(session, CassandraConfiguration.DEFAULT_CONFIGURATION);
-    }
-
     private PreparedStatement prepareSelect(Session session) {
         return session.prepare(select(NEXT_UID)
             .from(TABLE_NAME)
@@ -101,66 +94,56 @@ public class CassandraUidProvider implements UidProvider {
     public MessageUid nextUid(MailboxSession session, MailboxId mailboxId) throws MailboxException {
         CassandraId cassandraId = (CassandraId) mailboxId;
         return nextUid(cassandraId)
-        .join()
-        .orElseThrow(() -> new MailboxException("Error during Uid update"));
+            .blockOptional()
+            .orElseThrow(() -> new MailboxException("Error during Uid update"));
     }
 
-    public CompletableFuture<Optional<MessageUid>> nextUid(CassandraId cassandraId) {
-        return findHighestUid(cassandraId)
-            .thenCompose(optional -> {
-                if (optional.isPresent()) {
-                    return tryUpdateUid(cassandraId, optional);
-                }
-                return tryInsert(cassandraId);
-            })
-            .thenCompose(optional -> {
-                if (optional.isPresent()) {
-                    return CompletableFuture.completedFuture(optional);
-                }
-                return runner.executeAsyncAndRetrieveObject(
-                    () -> findHighestUid(cassandraId)
-                        .thenCompose(readUid -> tryUpdateUid(cassandraId, readUid)));
-            });
+    public Mono<MessageUid> nextUid(CassandraId cassandraId) {
+        Mono<MessageUid> updateUid = findHighestUid(cassandraId)
+            .flatMap(messageUid -> tryUpdateUid(cassandraId, messageUid));
+
+        return updateUid
+            .switchIfEmpty(tryInsert(cassandraId))
+            .switchIfEmpty(updateUid)
+            .single()
+            .retry(maxUidRetries);
     }
 
     @Override
     public Optional<MessageUid> lastUid(MailboxSession mailboxSession, Mailbox mailbox) throws MailboxException {
-        return findHighestUid((CassandraId) mailbox.getMailboxId()).join();
+        return findHighestUid((CassandraId) mailbox.getMailboxId())
+                .blockOptional();
     }
 
-    private CompletableFuture<Optional<MessageUid>> findHighestUid(CassandraId mailboxId) {
-        return executor.executeSingleRow(
+    private Mono<MessageUid> findHighestUid(CassandraId mailboxId) {
+        return Mono.defer(() -> executor.executeSingleRowReactor(
             selectStatement.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()))
-            .thenApply(optional -> optional.map(row -> MessageUid.of(row.getLong(NEXT_UID))));
+            .map(row -> MessageUid.of(row.getLong(NEXT_UID))));
     }
 
-    private CompletableFuture<Optional<MessageUid>> tryUpdateUid(CassandraId mailboxId, Optional<MessageUid> uid) {
-        if (uid.isPresent()) {
-            MessageUid nextUid = uid.get().next();
-            return executor.executeReturnApplied(
+    private Mono<MessageUid> tryUpdateUid(CassandraId mailboxId, MessageUid uid) {
+        MessageUid nextUid = uid.next();
+        return Mono.defer(() -> executor.executeReturnApplied(
                 updateStatement.bind()
-                    .setUUID(MAILBOX_ID, mailboxId.asUuid())
-                    .setLong(CONDITION, uid.get().asLong())
-                    .setLong(NEXT_UID, nextUid.asLong()))
-                .thenApply(success -> successToUid(nextUid, success));
-        } else {
-            return tryInsert(mailboxId);
-        }
+                        .setUUID(MAILBOX_ID, mailboxId.asUuid())
+                        .setLong(CONDITION, uid.asLong())
+                        .setLong(NEXT_UID, nextUid.asLong()))
+                .flatMap(success -> successToUid(nextUid, success)));
     }
 
-    private CompletableFuture<Optional<MessageUid>> tryInsert(CassandraId mailboxId) {
-        return executor.executeReturnApplied(
+    private Mono<MessageUid> tryInsert(CassandraId mailboxId) {
+        return Mono.defer(() -> executor.executeReturnApplied(
             insertStatement.bind()
                 .setUUID(MAILBOX_ID, mailboxId.asUuid()))
-            .thenApply(success -> successToUid(MessageUid.MIN_VALUE, success));
+            .flatMap(success -> successToUid(MessageUid.MIN_VALUE, success)));
     }
 
-    private Optional<MessageUid> successToUid(MessageUid uid, Boolean success) {
+    private Mono<MessageUid> successToUid(MessageUid uid, Boolean success) {
         if (success) {
-            return Optional.of(uid);
+            return Mono.just(uid);
         }
-        return Optional.empty();
+        return Mono.empty();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java
index 7f93150..4bfeafb 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAO.java
@@ -27,10 +27,8 @@ import static org.apache.james.mailbox.cassandra.table.CassandraUserMailboxRight
 import static org.apache.james.mailbox.cassandra.table.CassandraUserMailboxRightsTable.TABLE_NAME;
 import static org.apache.james.mailbox.cassandra.table.CassandraUserMailboxRightsTable.USER_NAME;
 
-import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import javax.inject.Inject;
@@ -44,13 +42,14 @@ import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.exception.UnsupportedRightException;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxACL.Rfc4314Rights;
-import org.apache.james.util.FluentFutureStream;
 
 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.github.fge.lambdas.Throwing;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraUserMailboxRightsDAO {
 
@@ -98,31 +97,32 @@ public class CassandraUserMailboxRightsDAO {
             .where(eq(USER_NAME, bindMarker(USER_NAME))));
     }
 
-    public CompletableFuture<Void> update(CassandraId cassandraId, ACLDiff aclDiff) {
+    public Mono<Void> update(CassandraId cassandraId, ACLDiff aclDiff) {
         PositiveUserACLDiff userACLDiff = new PositiveUserACLDiff(aclDiff);
-        return CompletableFuture.allOf(
+        return Flux.merge(
             addAll(cassandraId, userACLDiff.addedEntries()),
             removeAll(cassandraId, userACLDiff.removedEntries()),
-            addAll(cassandraId, userACLDiff.changedEntries()));
+            addAll(cassandraId, userACLDiff.changedEntries()))
+            .then();
     }
 
-    private CompletableFuture<Stream<Void>> removeAll(CassandraId cassandraId, Stream<MailboxACL.Entry> removedEntries) {
-        return FluentFutureStream.of(removedEntries
-            .map(entry -> cassandraAsyncExecutor.executeVoid(
+    private Mono<Void> removeAll(CassandraId cassandraId, Stream<MailboxACL.Entry> removedEntries) {
+        return Flux.fromStream(removedEntries)
+            .flatMap(entry -> cassandraAsyncExecutor.executeVoidReactor(
                 delete.bind()
                     .setString(USER_NAME, entry.getKey().getName())
-                    .setUUID(MAILBOX_ID, cassandraId.asUuid()))))
-        .completableFuture();
+                    .setUUID(MAILBOX_ID, cassandraId.asUuid())))
+            .then();
     }
 
-    private CompletableFuture<Stream<Void>> addAll(CassandraId cassandraId, Stream<MailboxACL.Entry> addedEntries) {
-        return FluentFutureStream.of(addedEntries
-            .map(entry -> cassandraAsyncExecutor.executeVoid(
+    private Mono<Void> addAll(CassandraId cassandraId, Stream<MailboxACL.Entry> addedEntries) {
+        return Flux.fromStream(addedEntries)
+            .flatMap(entry -> cassandraAsyncExecutor.executeVoidReactor(
                 insert.bind()
                     .setString(USER_NAME, entry.getKey().getName())
                     .setUUID(MAILBOX_ID, cassandraId.asUuid())
-                    .setString(RIGHTS, entry.getValue().serialize()))))
-        .completableFuture();
+                    .setString(RIGHTS, entry.getValue().serialize())))
+            .then();
     }
 
     public CompletableFuture<Optional<Rfc4314Rights>> retrieve(String userName, CassandraId mailboxId) {
@@ -134,14 +134,12 @@ public class CassandraUserMailboxRightsDAO {
                 rowOptional.map(Throwing.function(row -> Rfc4314Rights.fromSerializedRfc4314Rights(row.getString(RIGHTS)))));
     }
 
-    public CompletableFuture<Map<CassandraId, Rfc4314Rights>> listRightsForUser(String userName) {
-        return cassandraAsyncExecutor.execute(
+    public Flux<Pair<CassandraId, Rfc4314Rights>> listRightsForUser(String userName) {
+        return cassandraAsyncExecutor.executeReactor(
             selectUser.bind()
                 .setString(USER_NAME, userName))
-            .thenApply(cassandraUtils::convertToStream)
-            .thenApply(row ->
-                row.map(Throwing.function(this::toPair))
-                    .collect(Collectors.toMap(Pair::getLeft, Pair::getRight)));
+            .flatMapMany(cassandraUtils::convertToFlux)
+            .map(Throwing.function(this::toPair));
     }
 
     private Pair<CassandraId, Rfc4314Rights> toPair(Row row) throws UnsupportedRightException {

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
index d43c8a6..2ab5e56 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
@@ -25,10 +25,13 @@ import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO.MessageIdAttachmentIds;
+import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.task.Task;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import reactor.core.publisher.Flux;
+
 public class AttachmentMessageIdCreation implements Migration {
     private static final Logger LOGGER = LoggerFactory.getLogger(AttachmentMessageIdCreation.class);
     private final CassandraMessageDAO cassandraMessageDAO;
@@ -56,10 +59,11 @@ public class AttachmentMessageIdCreation implements Migration {
 
     private Result createIndex(MessageIdAttachmentIds message) {
         try {
-            message.getAttachmentId()
-                .forEach(attachmentId -> attachmentMessageIdDAO
-                    .storeAttachmentForMessageId(attachmentId, message.getMessageId())
-                    .join());
+            MessageId messageId = message.getMessageId();
+            Flux.fromIterable(message.getAttachmentId())
+                .flatMap(attachmentId -> attachmentMessageIdDAO.storeAttachmentForMessageId(attachmentId, messageId))
+                .then()
+                .block();
             return Result.COMPLETED;
         } catch (Exception e) {
             LOGGER.error("Error while creation attachmentId -> messageIds index", e);

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
index 148d395..bebf83d 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
@@ -61,7 +61,7 @@ public class AttachmentV2Migration implements Migration {
         try {
             blobStore.save(attachment.getBytes())
                 .thenApply(blobId -> CassandraAttachmentDAOV2.from(attachment, blobId))
-                .thenCompose(attachmentDAOV2::storeAttachment)
+                .thenCompose(daoAttachement -> attachmentDAOV2.storeAttachment(daoAttachement).toFuture())
                 .thenCompose(any -> attachmentDAOV1.deleteAttachment(attachment.getAttachmentId()))
                 .join();
             return Result.COMPLETED;

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2Migration.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2Migration.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2Migration.java
index 70f4a8e..c4f3fd2 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2Migration.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2Migration.java
@@ -80,9 +80,9 @@ public class MailboxPathV2Migration implements Migration {
 
     public Result migrate(CassandraIdAndPath idAndPath) {
         try {
-            daoV2.save(idAndPath.getMailboxPath(), idAndPath.getCassandraId()).join();
+            daoV2.save(idAndPath.getMailboxPath(), idAndPath.getCassandraId()).block();
 
-            daoV1.delete(idAndPath.getMailboxPath()).join();
+            daoV1.delete(idAndPath.getMailboxPath()).block();
             return Result.COMPLETED;
         } catch (Exception e) {
             LOGGER.error("Error while performing migration for path {}", idAndPath.getMailboxPath(), e);

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/MailboxMergingTaskRunner.java
----------------------------------------------------------------------
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 1a4a254..0032ef6 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
@@ -63,7 +63,7 @@ public class MailboxMergingTaskRunner {
         return moveMessages(oldMailboxId, newMailboxId, mailboxSession, context)
             .onComplete(
                 () -> mergeRights(oldMailboxId, newMailboxId),
-                () -> mailboxDAO.delete(oldMailboxId).join());
+                () -> mailboxDAO.delete(oldMailboxId).block());
     }
 
     private Task.Result moveMessages(CassandraId oldMailboxId, CassandraId newMailboxId, MailboxSession session, MailboxMergingTask.Context context) {
@@ -88,12 +88,12 @@ public class MailboxMergingTaskRunner {
 
     private void mergeRights(CassandraId oldMailboxId, CassandraId newMailboxId) {
         try {
-            MailboxACL oldAcl = cassandraACLMapper.getACL(oldMailboxId).join();
-            MailboxACL newAcl = cassandraACLMapper.getACL(newMailboxId).join();
+            MailboxACL oldAcl = cassandraACLMapper.getACL(oldMailboxId).block();
+            MailboxACL newAcl = cassandraACLMapper.getACL(newMailboxId).block();
             MailboxACL finalAcl = newAcl.union(oldAcl);
 
             cassandraACLMapper.setACL(newMailboxId, finalAcl);
-            rightsDAO.update(oldMailboxId, ACLDiff.computeDiff(oldAcl, MailboxACL.EMPTY)).join();
+            rightsDAO.update(oldMailboxId, ACLDiff.computeDiff(oldAcl, MailboxACL.EMPTY)).block();
         } catch (MailboxException e) {
             throw new RuntimeException(e);
         }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoaderTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoaderTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoaderTest.java
index d4b073d..4161e8d 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoaderTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoaderTest.java
@@ -23,21 +23,17 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.util.Collection;
-import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
 
 import org.apache.james.mailbox.model.Attachment;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.Cid;
 import org.apache.james.mailbox.model.MessageAttachment;
-import org.assertj.core.data.MapEntry;
 import org.junit.Before;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
+import reactor.core.publisher.Mono;
 
 public class AttachmentLoaderTest {
 
@@ -53,15 +49,15 @@ public class AttachmentLoaderTest {
     @Test
     public void getAttachmentsShouldWorkWithDuplicatedAttachments() {
         AttachmentId attachmentId = AttachmentId.from("1");
-        Set<AttachmentId> attachmentIds = ImmutableSet.of(attachmentId);
 
         Attachment attachment = Attachment.builder()
             .attachmentId(attachmentId)
             .bytes("attachment".getBytes())
             .type("type")
             .build();
-        when(attachmentMapper.getAttachmentsAsFuture(attachmentIds))
-            .thenReturn(CompletableFuture.completedFuture(ImmutableList.of(attachment)));
+
+        when(attachmentMapper.getAttachmentsAsMono(attachmentId))
+            .thenReturn(Mono.just(attachment));
 
         Optional<String> name = Optional.of("name1");
         Optional<Cid> cid = Optional.empty();
@@ -69,7 +65,7 @@ public class AttachmentLoaderTest {
         MessageAttachmentRepresentation attachmentRepresentation = new MessageAttachmentRepresentation(attachmentId, name, cid, isInlined);
 
         Collection<MessageAttachment> attachments = testee.getAttachments(ImmutableList.of(attachmentRepresentation, attachmentRepresentation))
-            .join();
+            .block();
 
         MessageAttachment expectedAttachment = new MessageAttachment(attachment, name, cid, isInlined);
         assertThat(attachments).hasSize(2)
@@ -79,15 +75,15 @@ public class AttachmentLoaderTest {
     @Test
     public void getAttachmentsShouldWorkWithDuplicatedIds() {
         AttachmentId attachmentId = AttachmentId.from("1");
-        Set<AttachmentId> attachmentIds = ImmutableSet.of(attachmentId);
 
         Attachment attachment = Attachment.builder()
             .attachmentId(attachmentId)
             .bytes("attachment".getBytes())
             .type("type")
             .build();
-        when(attachmentMapper.getAttachmentsAsFuture(attachmentIds))
-            .thenReturn(CompletableFuture.completedFuture(ImmutableList.of(attachment)));
+
+        when(attachmentMapper.getAttachmentsAsMono(attachmentId))
+                .thenReturn(Mono.just(attachment));
 
         Optional<String> name1 = Optional.of("name1");
         Optional<String> name2 = Optional.of("name2");
@@ -97,7 +93,7 @@ public class AttachmentLoaderTest {
         MessageAttachmentRepresentation attachmentRepresentation2 = new MessageAttachmentRepresentation(attachmentId, name2, cid, isInlined);
 
         Collection<MessageAttachment> attachments = testee.getAttachments(ImmutableList.of(attachmentRepresentation1, attachmentRepresentation2))
-            .join();
+            .block();
 
         assertThat(attachments).hasSize(2)
             .containsOnly(new MessageAttachment(attachment, name1, cid, isInlined),
@@ -108,7 +104,6 @@ public class AttachmentLoaderTest {
     public void getAttachmentsShouldReturnMultipleAttachmentWhenSeveralAttachmentsRepresentation() {
         AttachmentId attachmentId1 = AttachmentId.from("1");
         AttachmentId attachmentId2 = AttachmentId.from("2");
-        Set<AttachmentId> attachmentIds = ImmutableSet.of(attachmentId1, attachmentId2);
 
         Attachment attachment1 = Attachment.builder()
             .attachmentId(attachmentId1)
@@ -120,8 +115,11 @@ public class AttachmentLoaderTest {
             .bytes("attachment2".getBytes())
             .type("type")
             .build();
-        when(attachmentMapper.getAttachmentsAsFuture(attachmentIds))
-            .thenReturn(CompletableFuture.completedFuture(ImmutableList.of(attachment1, attachment2)));
+
+        when(attachmentMapper.getAttachmentsAsMono(attachmentId1))
+                .thenReturn(Mono.just(attachment1));
+        when(attachmentMapper.getAttachmentsAsMono(attachmentId2))
+                .thenReturn(Mono.just(attachment2));
 
         Optional<String> name1 = Optional.of("name1");
         Optional<String> name2 = Optional.of("name2");
@@ -131,7 +129,7 @@ public class AttachmentLoaderTest {
         MessageAttachmentRepresentation attachmentRepresentation2 = new MessageAttachmentRepresentation(attachmentId2, name2, cid, isInlined);
 
         Collection<MessageAttachment> attachments = testee.getAttachments(ImmutableList.of(attachmentRepresentation1, attachmentRepresentation2))
-            .join();
+            .block();
 
         assertThat(attachments).hasSize(2)
             .containsOnly(new MessageAttachment(attachment1, name1, cid, isInlined),
@@ -141,61 +139,19 @@ public class AttachmentLoaderTest {
     @Test
     public void getAttachmentsShouldReturnEmptyByDefault() {
         AttachmentId attachmentId = AttachmentId.from("1");
-        Set<AttachmentId> attachmentIds = ImmutableSet.of(attachmentId);
 
         Attachment attachment = Attachment.builder()
             .attachmentId(attachmentId)
             .bytes("attachment".getBytes())
             .type("type")
             .build();
-        when(attachmentMapper.getAttachmentsAsFuture(attachmentIds))
-            .thenReturn(CompletableFuture.completedFuture(ImmutableList.of(attachment)));
+
+        when(attachmentMapper.getAttachmentsAsMono(attachmentId))
+                .thenReturn(Mono.just(attachment));
 
         Collection<MessageAttachment> attachments = testee.getAttachments(ImmutableList.of())
-            .join();
+            .block();
 
         assertThat(attachments).isEmpty();
     }
-
-    @Test
-    public void attachmentsByIdShouldReturnMapWhenExist() {
-        AttachmentId attachmentId = AttachmentId.from("1");
-        AttachmentId attachmentId2 = AttachmentId.from("2");
-        Set<AttachmentId> attachmentIds = ImmutableSet.of(attachmentId, attachmentId2);
-
-        Attachment attachment = Attachment.builder()
-                .attachmentId(attachmentId)
-                .bytes("attachment".getBytes())
-                .type("type")
-                .build();
-        Attachment attachment2 = Attachment.builder()
-                .attachmentId(attachmentId2)
-                .bytes("attachment2".getBytes())
-                .type("type")
-                .build();
-        when(attachmentMapper.getAttachmentsAsFuture(attachmentIds))
-            .thenReturn(CompletableFuture.completedFuture(ImmutableList.of(attachment, attachment2)));
-
-        Map<AttachmentId, Attachment> attachmentsById = testee.attachmentsById(attachmentIds)
-            .join();
-
-        assertThat(attachmentsById).hasSize(2)
-                .containsOnly(MapEntry.entry(attachmentId, attachment), MapEntry.entry(attachmentId2, attachment2));
-    }
-
-    @Test
-    public void attachmentsByIdShouldReturnEmptyMapWhenAttachmentsDontExists() {
-        AttachmentId attachmentId = AttachmentId.from("1");
-        AttachmentId attachmentId2 = AttachmentId.from("2");
-        Set<AttachmentId> attachmentIds = ImmutableSet.of(attachmentId, attachmentId2);
-
-        when(attachmentMapper.getAttachmentsAsFuture(attachmentIds))
-                .thenReturn(CompletableFuture.completedFuture(ImmutableList.of()));
-
-        Map<AttachmentId, Attachment> attachmentsById = testee.attachmentsById(attachmentIds)
-            .join();
-
-        assertThat(attachmentsById).hasSize(0);
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java
----------------------------------------------------------------------
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 d9f7c89..8b94cdb 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
@@ -78,12 +78,12 @@ class CassandraACLMapperTest {
                 .value(CassandraACLTable.ACL, "{\"entries\":{\"bob\":invalid}}")
                 .value(CassandraACLTable.VERSION, 1));
 
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join()).isEqualTo(MailboxACL.EMPTY);
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(MailboxACL.EMPTY);
     }
 
     @Test
     void retrieveACLWhenNoACLStoredShouldReturnEmptyACL() {
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join()).isEqualTo(MailboxACL.EMPTY);
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(MailboxACL.EMPTY);
     }
 
     @Test
@@ -94,7 +94,7 @@ class CassandraACLMapperTest {
         cassandraACLMapper.updateACL(MAILBOX_ID,
             MailboxACL.command().key(key).rights(rights).asAddition());
 
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join())
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block())
             .isEqualTo(new MailboxACL().union(key, rights));
     }
 
@@ -107,7 +107,7 @@ class CassandraACLMapperTest {
         MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
         cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(keyAlice).rights(rights).asAddition());
 
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join())
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block())
             .isEqualTo(new MailboxACL().union(keyBob, rights).union(keyAlice, rights));
     }
 
@@ -119,7 +119,7 @@ class CassandraACLMapperTest {
         cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition());
         cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asRemoval());
 
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join()).isEqualTo(MailboxACL.EMPTY);
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(MailboxACL.EMPTY);
     }
 
     @Test
@@ -130,7 +130,7 @@ class CassandraACLMapperTest {
         cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition());
         cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).noRights().asReplacement());
 
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join()).isEqualTo(MailboxACL.EMPTY);
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(MailboxACL.EMPTY);
     }
 
     @Test
@@ -140,7 +140,7 @@ class CassandraACLMapperTest {
 
         cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asReplacement());
 
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join()).isEqualTo(new MailboxACL().union(key, rights));
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(new MailboxACL().union(key, rights));
     }
 
     @Test
@@ -155,11 +155,11 @@ class CassandraACLMapperTest {
 
         cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition());
 
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join()).isEqualTo(new MailboxACL().union(key, rights));
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block()).isEqualTo(new MailboxACL().union(key, rights));
     }
 
     @Test
-    void twoConcurrentUpdatesWhenNoACEStoredShouldReturnACEWithTwoEntries(CassandraCluster cassandra) throws Exception {
+    void twoConcurrentUpdatesWhenNoACLStoredShouldReturnACLWithTwoEntries(CassandraCluster cassandra) throws Exception {
         CountDownLatch countDownLatch = new CountDownLatch(2);
         MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
         MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
@@ -168,12 +168,12 @@ class CassandraACLMapperTest {
         Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights, countDownLatch::countDown);
         awaitAll(future1, future2);
 
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join())
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block())
             .isEqualTo(new MailboxACL().union(keyBob, rights).union(keyAlice, rights));
     }
 
     @Test
-    void twoConcurrentUpdatesWhenStoredShouldReturnACEWithTwoEntries(CassandraCluster cassandra) throws Exception {
+    void twoConcurrentUpdatesWhenStoredShouldReturnACLWithTwoEntries(CassandraCluster cassandra) throws Exception {
         CountDownLatch countDownLatch = new CountDownLatch(2);
         MailboxACL.EntryKey keyBenwa = new MailboxACL.EntryKey("benwa", MailboxACL.NameType.user, false);
         MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
@@ -185,7 +185,7 @@ class CassandraACLMapperTest {
         Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights, countDownLatch::countDown);
         awaitAll(future1, future2);
 
-        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join())
+        assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block())
             .isEqualTo(new MailboxACL().union(keyBob, rights).union(keyAlice, rights).union(keyBenwa, rights));
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOTest.java
index f82375e..6cd0b2f 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOTest.java
@@ -55,7 +55,7 @@ class CassandraAttachmentDAOTest {
 
     @Test
     void getAttachmentShouldReturnEmptyWhenAbsent() {
-        Optional<Attachment> attachment = testee.getAttachment(ATTACHMENT_ID).join();
+        Optional<Attachment> attachment = testee.getAttachment(ATTACHMENT_ID).blockOptional();
 
         assertThat(attachment).isEmpty();
     }
@@ -98,7 +98,7 @@ class CassandraAttachmentDAOTest {
             .build();
         testee.storeAttachment(attachment).join();
 
-        Optional<Attachment> actual = testee.getAttachment(ATTACHMENT_ID).join();
+        Optional<Attachment> actual = testee.getAttachment(ATTACHMENT_ID).blockOptional();
 
         assertThat(actual).contains(attachment);
     }
@@ -114,7 +114,7 @@ class CassandraAttachmentDAOTest {
 
         testee.deleteAttachment(attachment.getAttachmentId()).join();
 
-        assertThat(testee.getAttachment(attachment.getAttachmentId()).join())
+        assertThat(testee.getAttachment(attachment.getAttachmentId()).blockOptional())
             .isEmpty();
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentDAOV2Test.java
----------------------------------------------------------------------
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 6e3b705..2bf90c7 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
@@ -52,7 +52,7 @@ class CassandraAttachmentDAOV2Test {
 
     @Test
     void getAttachmentShouldReturnEmptyWhenAbsent() {
-        Optional<DAOAttachment> attachment = testee.getAttachment(ATTACHMENT_ID).join();
+        Optional<DAOAttachment> attachment = testee.getAttachment(ATTACHMENT_ID).blockOptional();
 
         assertThat(attachment).isEmpty();
     }
@@ -66,9 +66,9 @@ class CassandraAttachmentDAOV2Test {
             .build();
         BlobId blobId = BLOB_ID_FACTORY.from("blobId");
         DAOAttachment daoAttachment = CassandraAttachmentDAOV2.from(attachment, blobId);
-        testee.storeAttachment(daoAttachment).join();
+        testee.storeAttachment(daoAttachment).block();
 
-        Optional<DAOAttachment> actual = testee.getAttachment(ATTACHMENT_ID).join();
+        Optional<DAOAttachment> actual = testee.getAttachment(ATTACHMENT_ID).blockOptional();
 
         assertThat(actual).contains(daoAttachment);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java
index 862ea95..10492c6 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java
@@ -23,6 +23,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.nio.charset.StandardCharsets;
+import java.util.List;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
@@ -100,7 +101,7 @@ class CassandraAttachmentFallbackTest {
             .build();
 
         BlobId blobId = blobsDAO.save(attachment.getBytes()).join();
-        attachmentDAOV2.storeAttachment(CassandraAttachmentDAOV2.from(attachment, blobId)).join();
+        attachmentDAOV2.storeAttachment(CassandraAttachmentDAOV2.from(attachment, blobId)).block();
         attachmentDAO.storeAttachment(otherAttachment).join();
 
         assertThat(attachmentMapper.getAttachment(ATTACHMENT_ID_1))
@@ -135,7 +136,7 @@ class CassandraAttachmentFallbackTest {
             .build();
 
         BlobId blobId = blobsDAO.save(attachment.getBytes()).join();
-        attachmentDAOV2.storeAttachment(CassandraAttachmentDAOV2.from(attachment, blobId)).join();
+        attachmentDAOV2.storeAttachment(CassandraAttachmentDAOV2.from(attachment, blobId)).block();
         attachmentDAO.storeAttachment(otherAttachment).join();
 
         assertThat(attachmentMapper.getAttachments(ImmutableList.of(ATTACHMENT_ID_1)))
@@ -170,10 +171,11 @@ class CassandraAttachmentFallbackTest {
             .build();
 
         BlobId blobId = blobsDAO.save(attachment.getBytes()).join();
-        attachmentDAOV2.storeAttachment(CassandraAttachmentDAOV2.from(attachment, blobId)).join();
+        attachmentDAOV2.storeAttachment(CassandraAttachmentDAOV2.from(attachment, blobId)).block();
         attachmentDAO.storeAttachment(otherAttachment).join();
 
-        assertThat(attachmentMapper.getAttachments(ImmutableList.of(ATTACHMENT_ID_1, ATTACHMENT_ID_2)))
-            .containsExactly(attachment, otherAttachment);
+        List<Attachment> attachments = attachmentMapper.getAttachments(ImmutableList.of(ATTACHMENT_ID_1, ATTACHMENT_ID_2));
+        assertThat(attachments)
+            .containsExactlyInAnyOrder(attachment, otherAttachment);
     }
 }


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


[08/12] james-project git commit: JAMES-2630 Migrate CassandraAsyncExecutor.executeReturnApplied consumers to Reactor

Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAOTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAOTest.java
index f7d7b5d..0b87025 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentOwnerDAOTest.java
@@ -29,12 +29,13 @@ import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.mailbox.cassandra.modules.CassandraAttachmentModule;
 import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.store.mail.model.Username;
-import org.apache.james.util.FluentFutureStream;
 import org.apache.james.util.streams.JamesCollectors;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import reactor.core.publisher.Flux;
+
 class CassandraAttachmentOwnerDAOTest {
     private static final AttachmentId ATTACHMENT_ID = AttachmentId.from("id1");
     private static final Username OWNER_1 = Username.fromRawValue("owner1");
@@ -59,7 +60,7 @@ class CassandraAttachmentOwnerDAOTest {
 
     @Test
     void retrieveOwnersShouldReturnAddedOwner() {
-        testee.addOwner(ATTACHMENT_ID, OWNER_1).join();
+        testee.addOwner(ATTACHMENT_ID, OWNER_1).block();
 
         assertThat(testee.retrieveOwners(ATTACHMENT_ID).join())
             .containsOnly(OWNER_1);
@@ -67,8 +68,8 @@ class CassandraAttachmentOwnerDAOTest {
 
     @Test
     void retrieveOwnersShouldReturnAddedOwners() {
-        testee.addOwner(ATTACHMENT_ID, OWNER_1).join();
-        testee.addOwner(ATTACHMENT_ID, OWNER_2).join();
+        testee.addOwner(ATTACHMENT_ID, OWNER_1).block();
+        testee.addOwner(ATTACHMENT_ID, OWNER_2).block();
 
         assertThat(testee.retrieveOwners(ATTACHMENT_ID).join())
             .containsOnly(OWNER_1, OWNER_2);
@@ -81,10 +82,10 @@ class CassandraAttachmentOwnerDAOTest {
         IntStream.range(0, referenceCountExceedingPaging)
             .boxed()
             .collect(JamesCollectors.chunker(128))
-            .forEach(chunk -> FluentFutureStream.of(
-                chunk.stream()
-                    .map(i -> testee.addOwner(ATTACHMENT_ID, Username.fromRawValue("owner" + i))))
-                .join());
+            .forEach(chunk -> Flux.fromIterable(chunk)
+                    .flatMap(i -> testee.addOwner(ATTACHMENT_ID, Username.fromRawValue("owner" + i)))
+                    .then()
+                    .block());
 
         assertThat(testee.retrieveOwners(ATTACHMENT_ID).join())
             .hasSize(referenceCountExceedingPaging);

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAOTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAOTest.java
index 09dc1ee..4af1bdc 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxDAOTest.java
@@ -36,8 +36,6 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.github.steveash.guavate.Guavate;
-
 class CassandraMailboxDAOTest {
     private static final int UID_VALIDITY_1 = 145;
     private static final int UID_VALIDITY_2 = 147;
@@ -70,30 +68,30 @@ class CassandraMailboxDAOTest {
 
     @Test
     void retrieveMailboxShouldReturnEmptyWhenNone() {
-        assertThat(testee.retrieveMailbox(CASSANDRA_ID_1).join())
+        assertThat(testee.retrieveMailbox(CASSANDRA_ID_1).blockOptional())
             .isEmpty();
     }
 
     @Test
     void saveShouldAddAMailbox() {
-        testee.save(mailbox1).join();
+        testee.save(mailbox1).block();
 
         Optional<SimpleMailbox> readMailbox = testee.retrieveMailbox(CASSANDRA_ID_1)
-            .join();
+            .blockOptional();
         assertThat(readMailbox.isPresent()).isTrue();
         assertThat(readMailbox.get()).isEqualToComparingFieldByField(mailbox1);
     }
 
     @Test
     void saveShouldOverride() {
-        testee.save(mailbox1).join();
+        testee.save(mailbox1).block();
 
         mailbox2.setMailboxId(CASSANDRA_ID_1);
-        testee.save(mailbox2).join();
+        testee.save(mailbox2).block();
 
 
         Optional<SimpleMailbox> readMailbox = testee.retrieveMailbox(CASSANDRA_ID_1)
-            .join();
+            .blockOptional();
         assertThat(readMailbox.isPresent()).isTrue();
         assertThat(readMailbox.get()).isEqualToComparingFieldByField(mailbox2);
     }
@@ -101,47 +99,47 @@ class CassandraMailboxDAOTest {
     @Test
     void retrieveAllMailboxesShouldBeEmptyByDefault() {
         List<SimpleMailbox> mailboxes = testee.retrieveAllMailboxes()
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(mailboxes).isEmpty();
     }
 
     @Test
     void retrieveAllMailboxesShouldReturnSingleMailbox() {
-        testee.save(mailbox1).join();
+        testee.save(mailbox1).block();
 
         List<SimpleMailbox> mailboxes = testee.retrieveAllMailboxes()
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(mailboxes).containsOnly(mailbox1);
     }
 
     @Test
     void retrieveAllMailboxesShouldReturnMultiMailboxes() {
-        testee.save(mailbox1).join();
-        testee.save(mailbox2).join();
+        testee.save(mailbox1).block();
+        testee.save(mailbox2).block();
 
         List<SimpleMailbox> mailboxes = testee.retrieveAllMailboxes()
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(mailboxes).containsOnly(mailbox1, mailbox2);
     }
 
     @Test
     void deleteShouldNotFailWhenMailboxIsAbsent() {
-        testee.delete(CASSANDRA_ID_1).join();
+        testee.delete(CASSANDRA_ID_1).block();
     }
 
     @Test
     void deleteShouldRemoveExistingMailbox() {
-        testee.save(mailbox1).join();
+        testee.save(mailbox1).block();
 
-        testee.delete(CASSANDRA_ID_1).join();
+        testee.delete(CASSANDRA_ID_1).block();
 
-        assertThat(testee.retrieveMailbox(CASSANDRA_ID_1).join())
+        assertThat(testee.retrieveMailbox(CASSANDRA_ID_1).blockOptional())
             .isEmpty();
     }
 
@@ -152,14 +150,14 @@ class CassandraMailboxDAOTest {
 
     @Test
     void updateShouldChangeMailboxPath() {
-        testee.save(mailbox1).join();
+        testee.save(mailbox1).block();
 
         testee.updatePath(CASSANDRA_ID_1, NEW_MAILBOX_PATH).join();
 
         mailbox1.setNamespace(NEW_MAILBOX_PATH.getNamespace());
         mailbox1.setUser(NEW_MAILBOX_PATH.getUser());
         mailbox1.setName(NEW_MAILBOX_PATH.getName());
-        Optional<SimpleMailbox> readMailbox = testee.retrieveMailbox(CASSANDRA_ID_1).join();
+        Optional<SimpleMailbox> readMailbox = testee.retrieveMailbox(CASSANDRA_ID_1).blockOptional();
         assertThat(readMailbox.isPresent()).isTrue();
         assertThat(readMailbox.get()).isEqualToComparingFieldByField(mailbox1);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
index 1c3fb37..4ffa3dd 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
@@ -113,7 +113,7 @@ public class CassandraMailboxMapperTest {
             testee.save(newMailbox))
             .isInstanceOf(TooLongMailboxNameException.class);
 
-        assertThat(mailboxPathV2DAO.retrieveId(MAILBOX_PATH).join())
+        assertThat(mailboxPathV2DAO.retrieveId(MAILBOX_PATH).blockOptional())
             .isPresent();
     }
 
@@ -124,9 +124,9 @@ public class CassandraMailboxMapperTest {
     @Test
     public void deleteShouldDeleteMailboxAndMailboxPathFromV1Table() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
 
         testee.delete(MAILBOX);
 
@@ -137,9 +137,9 @@ public class CassandraMailboxMapperTest {
     @Test
     public void deleteShouldDeleteMailboxAndMailboxPathFromV2Table() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
 
         testee.delete(MAILBOX);
 
@@ -150,9 +150,9 @@ public class CassandraMailboxMapperTest {
     @Test
     public void findMailboxByPathShouldReturnMailboxWhenExistsInV1Table() throws Exception {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
 
         Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH);
 
@@ -162,9 +162,9 @@ public class CassandraMailboxMapperTest {
     @Test
     public void findMailboxByPathShouldReturnMailboxWhenExistsInV2Table() throws Exception {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
 
         Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH);
 
@@ -174,11 +174,11 @@ public class CassandraMailboxMapperTest {
     @Test
     public void findMailboxByPathShouldReturnMailboxWhenExistsInBothTables() throws Exception {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
 
         Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH);
 
@@ -188,11 +188,11 @@ public class CassandraMailboxMapperTest {
     @Test
     public void deleteShouldRemoveMailboxWhenInBothTables() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
 
         testee.delete(MAILBOX);
 
@@ -203,9 +203,9 @@ public class CassandraMailboxMapperTest {
     @Test
     public void deleteShouldRemoveMailboxWhenInV1Tables() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
 
         testee.delete(MAILBOX);
 
@@ -216,9 +216,9 @@ public class CassandraMailboxMapperTest {
     @Test
     public void deleteShouldRemoveMailboxWhenInV2Table() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
 
         testee.delete(MAILBOX);
 
@@ -229,7 +229,7 @@ public class CassandraMailboxMapperTest {
     @Test
     public void findMailboxByPathShouldThrowWhenDoesntExistInBothTables() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
 
         assertThatThrownBy(() -> testee.findMailboxByPath(MAILBOX_PATH))
             .isInstanceOf(MailboxNotFoundException.class);
@@ -238,9 +238,9 @@ public class CassandraMailboxMapperTest {
     @Test
     public void findMailboxWithPathLikeShouldReturnMailboxesWhenExistsInV1Table() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
     
         List<Mailbox> mailboxes = testee.findMailboxWithPathLike(new MailboxPath(MailboxConstants.USER_NAMESPACE, USER, WILDCARD));
 
@@ -250,11 +250,11 @@ public class CassandraMailboxMapperTest {
     @Test
     public void findMailboxWithPathLikeShouldReturnMailboxesWhenExistsInBothTables() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
 
         List<Mailbox> mailboxes = testee.findMailboxWithPathLike(new MailboxPath(MailboxConstants.USER_NAMESPACE, USER, WILDCARD));
 
@@ -264,9 +264,9 @@ public class CassandraMailboxMapperTest {
     @Test
     public void findMailboxWithPathLikeShouldReturnMailboxesWhenExistsInV2Table() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
     
         List<Mailbox> mailboxes = testee.findMailboxWithPathLike(new MailboxPath(MailboxConstants.USER_NAMESPACE, USER, WILDCARD));
 
@@ -276,16 +276,16 @@ public class CassandraMailboxMapperTest {
     @Test
     public void hasChildrenShouldReturnChildWhenExistsInV1Table() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
         CassandraId childMailboxId = CassandraId.timeBased();
         MailboxPath childMailboxPath = MailboxPath.forUser(USER, "name.child");
         Mailbox childMailbox = new SimpleMailbox(childMailboxPath, UID_VALIDITY, childMailboxId);
         mailboxDAO.save(childMailbox)
-            .join();
+            .block();
         mailboxPathDAO.save(childMailboxPath, childMailboxId)
-            .join();
+            .block();
     
         boolean hasChildren = testee.hasChildren(MAILBOX, '.');
 
@@ -295,18 +295,18 @@ public class CassandraMailboxMapperTest {
     @Test
     public void hasChildrenShouldReturnChildWhenExistsInBothTables() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
         CassandraId childMailboxId = CassandraId.timeBased();
         MailboxPath childMailboxPath = MailboxPath.forUser(USER, "name.child");
         Mailbox childMailbox = new SimpleMailbox(childMailboxPath, UID_VALIDITY, childMailboxId);
         mailboxDAO.save(childMailbox)
-            .join();
+            .block();
         mailboxPathDAO.save(childMailboxPath, childMailboxId)
-            .join();
+            .block();
 
         boolean hasChildren = testee.hasChildren(MAILBOX, '.');
 
@@ -316,16 +316,16 @@ public class CassandraMailboxMapperTest {
     @Test
     public void hasChildrenShouldReturnChildWhenExistsInV2Table() {
         mailboxDAO.save(MAILBOX)
-            .join();
+            .block();
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
-            .join();
+            .block();
         CassandraId childMailboxId = CassandraId.timeBased();
         MailboxPath childMailboxPath = MailboxPath.forUser(USER, "name.child");
         Mailbox childMailbox = new SimpleMailbox(childMailboxPath, UID_VALIDITY, childMailboxId);
         mailboxDAO.save(childMailbox)
-            .join();
+            .block();
         mailboxPathV2DAO.save(childMailboxPath, childMailboxId)
-            .join();
+            .block();
     
         boolean hasChildren = testee.hasChildren(MAILBOX, '.');
     
@@ -334,11 +334,11 @@ public class CassandraMailboxMapperTest {
 
     @Test
     public void findMailboxWithPathLikeShouldRemoveDuplicatesAndKeepV2() {
-        mailboxDAO.save(MAILBOX).join();
-        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID).join();
+        mailboxDAO.save(MAILBOX).block();
+        mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID).block();
 
-        mailboxDAO.save(MAILBOX_BIS).join();
-        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID_2).join();
+        mailboxDAO.save(MAILBOX_BIS).block();
+        mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID_2).block();
 
         assertThat(testee.findMailboxWithPathLike(
             new MailboxPath(MailboxConstants.USER_NAMESPACE, USER, WILDCARD)))

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImplTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImplTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImplTest.java
index 429b8af..dbf64f2 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImplTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOImplTest.java
@@ -35,9 +35,9 @@ class CassandraMailboxPathDAOImplTest extends CassandraMailboxPathDAOTest {
 
     @Test
     void countAllShouldReturnEntryCount() {
-        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join();
-        testee.save(USER_OUTBOX_MAILBOXPATH, OUTBOX_ID).join();
-        testee.save(OTHER_USER_MAILBOXPATH, otherMailboxId).join();
+        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).block();
+        testee.save(USER_OUTBOX_MAILBOXPATH, OUTBOX_ID).block();
+        testee.save(OTHER_USER_MAILBOXPATH, otherMailboxId).block();
 
         CassandraMailboxPathDAOImpl daoV1 = (CassandraMailboxPathDAOImpl) testee;
 
@@ -55,9 +55,9 @@ class CassandraMailboxPathDAOImplTest extends CassandraMailboxPathDAOTest {
 
     @Test
     void readAllShouldReturnAllStoredData() {
-        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join();
-        testee.save(USER_OUTBOX_MAILBOXPATH, OUTBOX_ID).join();
-        testee.save(OTHER_USER_MAILBOXPATH, otherMailboxId).join();
+        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).block();
+        testee.save(USER_OUTBOX_MAILBOXPATH, OUTBOX_ID).block();
+        testee.save(OTHER_USER_MAILBOXPATH, otherMailboxId).block();
 
         CassandraMailboxPathDAOImpl daoV1 = (CassandraMailboxPathDAOImpl) testee;
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOTest.java
index 43592ae..acd6245 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOTest.java
@@ -34,8 +34,6 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.github.steveash.guavate.Guavate;
-
 import nl.jqno.equalsverifier.EqualsVerifier;
 
 public abstract class CassandraMailboxPathDAOTest {
@@ -70,43 +68,42 @@ public abstract class CassandraMailboxPathDAOTest {
 
     @Test
     void saveShouldInsertNewEntry() {
-        assertThat(testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join()).isTrue();
+        assertThat(testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).block()).isTrue();
 
-        assertThat(testee.retrieveId(USER_INBOX_MAILBOXPATH).join())
+        assertThat(testee.retrieveId(USER_INBOX_MAILBOXPATH).blockOptional())
             .contains(INBOX_ID_AND_PATH);
     }
 
     @Test
     void saveOnSecondShouldBeFalse() {
-        assertThat(testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join()).isTrue();
-        assertThat(testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join()).isFalse();
+        assertThat(testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).block()).isTrue();
+        assertThat(testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).block()).isFalse();
     }
 
     @Test
     void retrieveIdShouldReturnEmptyWhenEmptyData() {
-        assertThat(testee.retrieveId(USER_INBOX_MAILBOXPATH).join()
-            .isPresent())
-            .isFalse();
+        assertThat(testee.retrieveId(USER_INBOX_MAILBOXPATH).blockOptional())
+            .isEmpty();
     }
 
     @Test
     void retrieveIdShouldReturnStoredData() {
-        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join();
+        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).block();
 
-        assertThat(testee.retrieveId(USER_INBOX_MAILBOXPATH).join())
+        assertThat(testee.retrieveId(USER_INBOX_MAILBOXPATH).blockOptional())
             .contains(INBOX_ID_AND_PATH);
     }
 
     @Test
     void getUserMailboxesShouldReturnAllMailboxesOfUser() {
-        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join();
-        testee.save(USER_OUTBOX_MAILBOXPATH, OUTBOX_ID).join();
-        testee.save(OTHER_USER_MAILBOXPATH, otherMailboxId).join();
+        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).block();
+        testee.save(USER_OUTBOX_MAILBOXPATH, OUTBOX_ID).block();
+        testee.save(OTHER_USER_MAILBOXPATH, otherMailboxId).block();
 
         List<CassandraIdAndPath> cassandraIds = testee
             .listUserMailboxes(USER_INBOX_MAILBOXPATH.getNamespace(), USER_INBOX_MAILBOXPATH.getUser())
-            .join()
-            .collect(Guavate.toImmutableList());
+            .collectList()
+            .block();
 
         assertThat(cassandraIds)
             .hasSize(2)
@@ -115,16 +112,16 @@ public abstract class CassandraMailboxPathDAOTest {
 
     @Test
     void deleteShouldNotThrowWhenEmpty() {
-        testee.delete(USER_INBOX_MAILBOXPATH).join();
+        testee.delete(USER_INBOX_MAILBOXPATH).block();
     }
 
     @Test
     void deleteShouldDeleteTheExistingMailboxId() {
-        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join();
+        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).block();
 
-        testee.delete(USER_INBOX_MAILBOXPATH).join();
+        testee.delete(USER_INBOX_MAILBOXPATH).block();
 
-        assertThat(testee.retrieveId(USER_INBOX_MAILBOXPATH).join())
+        assertThat(testee.retrieveId(USER_INBOX_MAILBOXPATH).blockOptional())
             .isEmpty();
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java
index 95df7fb..914d1e9 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java
@@ -21,6 +21,7 @@ package org.apache.james.mailbox.cassandra.mail;
 import java.util.List;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MailboxSessionUtil;
 import org.apache.james.mailbox.MessageUid;
@@ -55,7 +56,7 @@ public class CassandraMapperProvider implements MapperProvider {
     public CassandraMapperProvider(CassandraCluster cassandra) {
         this.cassandra = cassandra;
         messageUidProvider = new MessageUidProvider();
-        cassandraModSeqProvider = new CassandraModSeqProvider(this.cassandra.getConf());
+        cassandraModSeqProvider = new CassandraModSeqProvider(this.cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION);
         mapperFactory = createMapperFactory();
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java
index da90b78..4eabd41 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOTest.java
@@ -26,7 +26,6 @@ import java.nio.charset.StandardCharsets;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
-import java.util.concurrent.CompletableFuture;
 import java.util.stream.Stream;
 
 import javax.mail.Flags;
@@ -64,6 +63,7 @@ import com.google.common.collect.ImmutableSet;
 import com.google.common.primitives.Bytes;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
+import reactor.core.publisher.Flux;
 
 class CassandraMessageDAOTest {
     private static final int BODY_START = 16;
@@ -186,8 +186,8 @@ class CassandraMessageDAOTest {
             .build();
     }
 
-    private MessageWithoutAttachment toMessage(CompletableFuture<Stream<CassandraMessageDAO.MessageResult>> readOptional) throws InterruptedException, java.util.concurrent.ExecutionException {
-        return readOptional.join()
+    private MessageWithoutAttachment toMessage(Flux<CassandraMessageDAO.MessageResult> read) throws InterruptedException, java.util.concurrent.ExecutionException {
+        return read.toStream()
             .map(CassandraMessageDAO.MessageResult::message)
             .map(Pair::getLeft)
             .findAny()

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
index 26947ab..67b9c90 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
@@ -57,7 +57,7 @@ class CassandraMessageIdDAOTest {
     @Test
     void deleteShouldNotThrowWhenRowDoesntExist() {
         testee.delete(CassandraId.timeBased(), MessageUid.of(1))
-            .join();
+            .block();
     }
 
     @Test
@@ -72,7 +72,7 @@ class CassandraMessageIdDAOTest {
                 .build())
             .join();
 
-        testee.delete(mailboxId, messageUid).join();
+        testee.delete(mailboxId, messageUid).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.isPresent()).isFalse();
@@ -98,7 +98,7 @@ class CassandraMessageIdDAOTest {
                     .build()))
         .join();
 
-        testee.delete(mailboxId, messageUid).join();
+        testee.delete(mailboxId, messageUid).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.isPresent()).isFalse();
@@ -142,7 +142,7 @@ class CassandraMessageIdDAOTest {
                 .flags(new Flags())
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId).join();
+        testee.updateMetadata(expectedComposedMessageId).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
@@ -167,7 +167,7 @@ class CassandraMessageIdDAOTest {
                 .flags(new Flags(Flag.ANSWERED))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId).join();
+        testee.updateMetadata(expectedComposedMessageId).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
@@ -192,7 +192,7 @@ class CassandraMessageIdDAOTest {
                 .flags(new Flags(Flag.DELETED))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId).join();
+        testee.updateMetadata(expectedComposedMessageId).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
@@ -217,7 +217,7 @@ class CassandraMessageIdDAOTest {
                 .flags(new Flags(Flag.DRAFT))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId).join();
+        testee.updateMetadata(expectedComposedMessageId).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
@@ -242,7 +242,7 @@ class CassandraMessageIdDAOTest {
                 .flags(new Flags(Flag.FLAGGED))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId).join();
+        testee.updateMetadata(expectedComposedMessageId).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
@@ -267,7 +267,7 @@ class CassandraMessageIdDAOTest {
                 .flags(new Flags(Flag.RECENT))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId).join();
+        testee.updateMetadata(expectedComposedMessageId).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
@@ -292,7 +292,7 @@ class CassandraMessageIdDAOTest {
                 .flags(new Flags(Flag.SEEN))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId).join();
+        testee.updateMetadata(expectedComposedMessageId).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
@@ -317,7 +317,7 @@ class CassandraMessageIdDAOTest {
                 .flags(new Flags(Flag.USER))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId).join();
+        testee.updateMetadata(expectedComposedMessageId).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);
@@ -344,7 +344,7 @@ class CassandraMessageIdDAOTest {
                 .flags(flags)
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId).join();
+        testee.updateMetadata(expectedComposedMessageId).block();
 
         Optional<ComposedMessageIdWithMetaData> message = testee.retrieve(mailboxId, messageUid).join();
         assertThat(message.get()).isEqualTo(expectedComposedMessageId);

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
index a200680..f563e5f 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
@@ -20,9 +20,9 @@ package org.apache.james.mailbox.cassandra.mail;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
 
 import javax.mail.Flags;
 import javax.mail.Flags.Flag;
@@ -42,12 +42,14 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
 import com.datastax.driver.core.utils.UUIDs;
-import com.github.steveash.guavate.Guavate;
 
 class CassandraMessageIdToImapUidDAOTest {
+    public static final CassandraModule MODULE = CassandraModule.aggregateModules(
+            CassandraSchemaVersionModule.MODULE,
+            CassandraMessageModule.MODULE);
+
     @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraModule.aggregateModules(
-        CassandraMessageModule.MODULE, CassandraSchemaVersionModule.MODULE));
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULE);
 
     private CassandraMessageId.Factory messageIdFactory;
 
@@ -62,7 +64,7 @@ class CassandraMessageIdToImapUidDAOTest {
     @Test
     void deleteShouldNotThrowWhenRowDoesntExist() {
         testee.delete(messageIdFactory.of(UUIDs.timeBased()), CassandraId.timeBased())
-            .join();
+            .block();
     }
 
     @Test
@@ -77,10 +79,10 @@ class CassandraMessageIdToImapUidDAOTest {
                     .build())
                 .join();
 
-        testee.delete(messageId, mailboxId).join();
+        testee.delete(messageId, mailboxId).block();
 
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).isEmpty();
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).isEmpty();
     }
 
     @Test
@@ -103,15 +105,15 @@ class CassandraMessageIdToImapUidDAOTest {
                     .build()))
         .join();
 
-        testee.delete(messageId, mailboxId).join();
+        testee.delete(messageId, mailboxId).block();
 
         ComposedMessageIdWithMetaData expectedComposedMessageId = ComposedMessageIdWithMetaData.builder()
                 .composedMessageId(new ComposedMessageId(mailboxId2, messageId, messageUid2))
                 .flags(new Flags())
                 .modSeq(1)
                 .build();
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.empty()).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.empty()).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -132,8 +134,8 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags())
                 .modSeq(1)
                 .build();
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -149,7 +151,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .build();
         testee.insert(composedMessageIdWithFlags).join();
 
-        Boolean result = testee.updateMetadata(composedMessageIdWithFlags, 1).join();
+        Boolean result = testee.updateMetadata(composedMessageIdWithFlags, 1).block();
 
         assertThat(result).isTrue();
     }
@@ -167,7 +169,7 @@ class CassandraMessageIdToImapUidDAOTest {
                 .build();
         testee.insert(composedMessageIdWithFlags).join();
 
-        Boolean result = testee.updateMetadata(composedMessageIdWithFlags, 3).join();
+        Boolean result = testee.updateMetadata(composedMessageIdWithFlags, 3).block();
 
         assertThat(result).isFalse();
     }
@@ -191,10 +193,10 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags())
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId, 1).join();
+        testee.updateMetadata(expectedComposedMessageId, 1).block();
 
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -216,10 +218,10 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags(Flag.ANSWERED))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId, 1).join();
+        testee.updateMetadata(expectedComposedMessageId, 1).block();
 
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -241,10 +243,10 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags(Flag.DELETED))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId, 1).join();
+        testee.updateMetadata(expectedComposedMessageId, 1).block();
 
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -266,10 +268,10 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags(Flag.DRAFT))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId, 1).join();
+        testee.updateMetadata(expectedComposedMessageId, 1).block();
 
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -291,10 +293,10 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags(Flag.FLAGGED))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId, 1).join();
+        testee.updateMetadata(expectedComposedMessageId, 1).block();
 
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -316,10 +318,10 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags(Flag.RECENT))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId, 1).join();
+        testee.updateMetadata(expectedComposedMessageId, 1).block();
 
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -341,10 +343,11 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags(Flag.SEEN))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId, 1).join();
+        assertThat(testee.updateMetadata(expectedComposedMessageId, 1).block())
+            .isTrue();
 
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -366,10 +369,10 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags(Flag.USER))
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId, 1).join();
+        testee.updateMetadata(expectedComposedMessageId, 1).block();
 
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -393,10 +396,10 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(flags)
                 .modSeq(2)
                 .build();
-        testee.updateMetadata(expectedComposedMessageId, 1).join();
+        testee.updateMetadata(expectedComposedMessageId, 1).block();
 
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -416,9 +419,9 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags())
                 .modSeq(1)
                 .build();
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).join();
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.of(mailboxId)).collectList().block();
 
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId);
+        assertThat(messages).containsOnly(expectedComposedMessageId);
     }
 
     @Test
@@ -451,8 +454,8 @@ class CassandraMessageIdToImapUidDAOTest {
                 .flags(new Flags())
                 .modSeq(1)
                 .build();
-        Stream<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.empty()).join();
+        List<ComposedMessageIdWithMetaData> messages = testee.retrieve(messageId, Optional.empty()).collectList().block();
 
-        assertThat(messages.collect(Guavate.toImmutableList())).containsOnly(expectedComposedMessageId, expectedComposedMessageId2);
+        assertThat(messages).containsOnly(expectedComposedMessageId, expectedComposedMessageId2);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProviderTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProviderTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProviderTest.java
index a0b691d..a8a2722 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProviderTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraModSeqProviderTest.java
@@ -20,14 +20,19 @@ package org.apache.james.mailbox.cassandra.mail;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.time.Duration;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.ExecutionException;
 import java.util.stream.LongStream;
 
 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.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.modules.CassandraModSeqModule;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
+import org.apache.james.util.concurrency.ConcurrentTestRunner;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
@@ -46,7 +51,7 @@ class CassandraModSeqProviderTest {
 
     @BeforeEach
     void setUp(CassandraCluster cassandra) {
-        modSeqProvider = new CassandraModSeqProvider(cassandra.getConf());
+        modSeqProvider = new CassandraModSeqProvider(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION);
         MailboxPath path = new MailboxPath("gsoc", "ieugen", "Trash");
         mailbox = new SimpleMailbox(path, 1234);
         mailbox.setMailboxId(CASSANDRA_ID);
@@ -77,13 +82,17 @@ class CassandraModSeqProviderTest {
     }
 
     @Test
-    void nextModSeqShouldGenerateUniqueValuesWhenParallelCalls() {
-        int nbEntries = 100;
-        long nbValues = LongStream.range(0, nbEntries)
-            .parallel()
-            .map(Throwing.longUnaryOperator(x -> modSeqProvider.nextModSeq(null, mailbox)))
-            .distinct()
-            .count();
-        assertThat(nbValues).isEqualTo(nbEntries);
+    void nextModSeqShouldGenerateUniqueValuesWhenParallelCalls() throws ExecutionException, InterruptedException {
+        int nbEntries = 10;
+
+        ConcurrentSkipListSet<Long> modSeqs = new ConcurrentSkipListSet<>();
+        ConcurrentTestRunner.builder()
+            .operation(
+                (threadNumber, step) -> modSeqs.add(modSeqProvider.nextModSeq(null, mailbox)))
+            .threadCount(10)
+            .operationCount(nbEntries)
+            .runSuccessfullyWithin(Duration.ofMinutes(1));
+
+        assertThat(modSeqs).hasSize(100);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProviderTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProviderTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProviderTest.java
index 619ced7..5a3fe69 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProviderTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProviderTest.java
@@ -20,16 +20,21 @@ package org.apache.james.mailbox.cassandra.mail;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.time.Duration;
 import java.util.Optional;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.ExecutionException;
 import java.util.stream.LongStream;
 
 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.mailbox.MessageUid;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.modules.CassandraUidModule;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
+import org.apache.james.util.concurrency.ConcurrentTestRunner;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
@@ -47,7 +52,7 @@ class CassandraUidProviderTest {
 
     @BeforeEach
     void setUp(CassandraCluster cassandra) {
-        uidProvider = new CassandraUidProvider(cassandra.getConf());
+        uidProvider = new CassandraUidProvider(cassandra.getConf(), CassandraConfiguration.DEFAULT_CONFIGURATION);
         MailboxPath path = new MailboxPath("gsoc", "ieugen", "Trash");
         mailbox = new SimpleMailbox(path, 1234);
         mailbox.setMailboxId(CASSANDRA_ID);
@@ -77,14 +82,17 @@ class CassandraUidProviderTest {
     }
 
     @Test
-    void nextUidShouldGenerateUniqueValuesWhenParallelCalls() {
+    void nextUidShouldGenerateUniqueValuesWhenParallelCalls() throws ExecutionException, InterruptedException {
+        int threadCount = 10;
         int nbEntries = 100;
-        long nbValues = LongStream.range(0, nbEntries)
-            .parallel()
-            .boxed()
-            .map(Throwing.function(x -> uidProvider.nextUid(null, mailbox)))
-            .distinct()
-            .count();
-        assertThat(nbValues).isEqualTo(nbEntries);
+
+        ConcurrentSkipListSet<MessageUid> messageUids = new ConcurrentSkipListSet<>();
+        ConcurrentTestRunner.builder()
+                .operation((threadNumber, step) -> messageUids.add(uidProvider.nextUid(null, mailbox)))
+            .threadCount(threadCount)
+            .operationCount(nbEntries / threadCount)
+            .runSuccessfullyWithin(Duration.ofMinutes(1));
+
+        assertThat(messageUids).hasSize(nbEntries);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAOTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAOTest.java
index 9730bda..1596e1c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUserMailboxRightsDAOTest.java
@@ -57,7 +57,7 @@ class CassandraUserMailboxRightsDAOTest {
         testee.update(MAILBOX_ID, ACLDiff.computeDiff(
             MailboxACL.EMPTY,
             new MailboxACL(new Entry(ENTRY_KEY, RIGHTS))))
-            .join();
+            .block();
 
         assertThat(testee.retrieve(USER_NAME, MAILBOX_ID).join())
             .contains(RIGHTS);
@@ -68,12 +68,12 @@ class CassandraUserMailboxRightsDAOTest {
         testee.update(MAILBOX_ID, ACLDiff.computeDiff(
             MailboxACL.EMPTY,
             new MailboxACL(new Entry(ENTRY_KEY, RIGHTS))))
-            .join();
+            .block();
 
         testee.update(MAILBOX_ID, ACLDiff.computeDiff(
             new MailboxACL(new Entry(ENTRY_KEY, RIGHTS)),
             new MailboxACL(new Entry(ENTRY_KEY, OTHER_RIGHTS))))
-            .join();
+            .block();
 
         assertThat(testee.retrieve(USER_NAME, MAILBOX_ID).join())
             .contains(OTHER_RIGHTS);
@@ -81,7 +81,7 @@ class CassandraUserMailboxRightsDAOTest {
 
     @Test
     void listRightsForUserShouldReturnEmptyWhenEmptyData() {
-        assertThat(testee.listRightsForUser(USER_NAME).join())
+        assertThat(testee.listRightsForUser(USER_NAME).collectList().block())
             .isEmpty();
     }
 
@@ -90,13 +90,13 @@ class CassandraUserMailboxRightsDAOTest {
         testee.update(MAILBOX_ID, ACLDiff.computeDiff(
             MailboxACL.EMPTY,
             new MailboxACL(new Entry(ENTRY_KEY, RIGHTS))))
-            .join();
+            .block();
 
 
         testee.update(MAILBOX_ID, ACLDiff.computeDiff(
             new MailboxACL(new Entry(ENTRY_KEY, RIGHTS)),
             MailboxACL.EMPTY))
-            .join();
+            .block();
 
         assertThat(testee.retrieve(USER_NAME, MAILBOX_ID).join())
             .isEmpty();

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
index a298106..85616b1 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
@@ -46,6 +46,8 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import reactor.core.publisher.Mono;
+
 class AttachmentV2MigrationTest {
     private static final AttachmentId ATTACHMENT_ID = AttachmentId.from("id1");
     private static final AttachmentId ATTACHMENT_ID_2 = AttachmentId.from("id2");
@@ -107,9 +109,9 @@ class AttachmentV2MigrationTest {
 
         migration.run();
 
-        assertThat(attachmentDAOV2.getAttachment(ATTACHMENT_ID).join())
+        assertThat(attachmentDAOV2.getAttachment(ATTACHMENT_ID).blockOptional())
             .contains(CassandraAttachmentDAOV2.from(attachment1, BLOB_ID_FACTORY.forPayload(attachment1.getBytes())));
-        assertThat(attachmentDAOV2.getAttachment(ATTACHMENT_ID_2).join())
+        assertThat(attachmentDAOV2.getAttachment(ATTACHMENT_ID_2).blockOptional())
             .contains(CassandraAttachmentDAOV2.from(attachment2, BLOB_ID_FACTORY.forPayload(attachment2.getBytes())));
         assertThat(blobsDAO.readBytes(BLOB_ID_FACTORY.forPayload(attachment1.getBytes())).join())
             .isEqualTo(attachment1.getBytes());
@@ -124,9 +126,9 @@ class AttachmentV2MigrationTest {
 
         migration.run();
 
-        assertThat(attachmentDAO.getAttachment(ATTACHMENT_ID).join())
+        assertThat(attachmentDAO.getAttachment(ATTACHMENT_ID).blockOptional())
             .isEmpty();
-        assertThat(attachmentDAO.getAttachment(ATTACHMENT_ID_2).join())
+        assertThat(attachmentDAO.getAttachment(ATTACHMENT_ID_2).blockOptional())
             .isEmpty();
     }
 
@@ -190,7 +192,7 @@ class AttachmentV2MigrationTest {
             .thenReturn(CompletableFuture.completedFuture(BLOB_ID_FACTORY.forPayload(attachment1.getBytes())));
         when(blobsDAO.save(attachment2.getBytes()))
             .thenReturn(CompletableFuture.completedFuture(BLOB_ID_FACTORY.forPayload(attachment2.getBytes())));
-        when(attachmentDAOV2.storeAttachment(any())).thenReturn(CompletableFuture.completedFuture(null));
+        when(attachmentDAOV2.storeAttachment(any())).thenReturn(Mono.empty());
         when(attachmentDAO.deleteAttachment(any())).thenThrow(new RuntimeException());
 
         assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
@@ -210,7 +212,7 @@ class AttachmentV2MigrationTest {
             .thenReturn(CompletableFuture.completedFuture(BLOB_ID_FACTORY.forPayload(attachment1.getBytes())));
         when(blobsDAO.save(attachment2.getBytes()))
             .thenThrow(new RuntimeException());
-        when(attachmentDAOV2.storeAttachment(any())).thenReturn(CompletableFuture.completedFuture(null));
+        when(attachmentDAOV2.storeAttachment(any())).thenReturn(Mono.empty());
         when(attachmentDAO.deleteAttachment(any())).thenReturn(CompletableFuture.completedFuture(null));
 
         assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
index cf19f73..f17ab80 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
@@ -91,7 +91,7 @@ class MailboxPathV2MigrationTest {
     void newValuesShouldBeSavedInMostRecentDAO() throws Exception {
         mailboxMapper.save(MAILBOX_1);
 
-        assertThat(daoV2.retrieveId(MAILBOX_PATH_1).join())
+        assertThat(daoV2.retrieveId(MAILBOX_PATH_1).blockOptional())
             .contains(new CassandraIdAndPath(MAILBOX_ID_1, MAILBOX_PATH_1));
     }
 
@@ -99,33 +99,33 @@ class MailboxPathV2MigrationTest {
     void newValuesShouldNotBeSavedInOldDAO() throws Exception {
         mailboxMapper.save(MAILBOX_1);
 
-        assertThat(daoV1.retrieveId(MAILBOX_PATH_1).join())
+        assertThat(daoV1.retrieveId(MAILBOX_PATH_1).blockOptional())
             .isEmpty();
     }
 
     @Test
     void readingOldValuesShouldMigrateThem() throws Exception {
-        daoV1.save(MAILBOX_PATH_1, MAILBOX_ID_1).join();
-        mailboxDAO.save(MAILBOX_1).join();
+        daoV1.save(MAILBOX_PATH_1, MAILBOX_ID_1).block();
+        mailboxDAO.save(MAILBOX_1).block();
 
         mailboxMapper.findMailboxByPath(MAILBOX_PATH_1);
 
         SoftAssertions softly = new SoftAssertions();
-        softly.assertThat(daoV1.retrieveId(MAILBOX_PATH_1).join()).isEmpty();
-        softly.assertThat(daoV2.retrieveId(MAILBOX_PATH_1).join())
+        softly.assertThat(daoV1.retrieveId(MAILBOX_PATH_1).blockOptional()).isEmpty();
+        softly.assertThat(daoV2.retrieveId(MAILBOX_PATH_1).blockOptional())
             .contains(new CassandraIdAndPath(MAILBOX_ID_1, MAILBOX_PATH_1));
         softly.assertAll();
     }
 
     @Test
     void migrationTaskShouldMoveDataToMostRecentDao() {
-        daoV1.save(MAILBOX_PATH_1, MAILBOX_ID_1).join();
+        daoV1.save(MAILBOX_PATH_1, MAILBOX_ID_1).block();
 
         new MailboxPathV2Migration(daoV1, daoV2).run();
 
         SoftAssertions softly = new SoftAssertions();
-        softly.assertThat(daoV1.retrieveId(MAILBOX_PATH_1).join()).isEmpty();
-        softly.assertThat(daoV2.retrieveId(MAILBOX_PATH_1).join())
+        softly.assertThat(daoV1.retrieveId(MAILBOX_PATH_1).blockOptional()).isEmpty();
+        softly.assertThat(daoV2.retrieveId(MAILBOX_PATH_1).blockOptional())
             .contains(new CassandraIdAndPath(MAILBOX_ID_1, MAILBOX_PATH_1));
         softly.assertAll();
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java
index 637cc69..9c43818 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java
@@ -26,11 +26,16 @@ import java.io.InputStream;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
+import java.util.stream.Stream;
 
+import com.github.fge.lambdas.Throwing;
+import com.google.common.collect.ImmutableList;
+import org.apache.commons.io.IOUtils;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MailboxSessionUtil;
 import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.model.Attachment;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.mailbox.model.MessageRange;
@@ -149,10 +154,20 @@ public abstract class AbstractMailboxManagerAttachmentTest {
         assertThat(messages.hasNext()).isTrue();
         List<MessageAttachment> attachments = messages.next().getAttachments();
         assertThat(attachments).hasSize(2);
-        assertThat(attachmentMapper.getAttachment(attachments.get(0).getAttachmentId()).getStream())
-            .hasSameContentAs(ClassLoader.getSystemResourceAsStream("eml/4037_014.jpg"));
-        assertThat(attachmentMapper.getAttachment(attachments.get(1).getAttachmentId()).getStream())
-            .hasSameContentAs(ClassLoader.getSystemResourceAsStream("eml/4037_015.jpg"));
+        ImmutableList<byte[]> attachmentContents = attachments
+            .stream()
+            .map(MessageAttachment::getAttachmentId)
+            .map(Throwing.function(attachmentMapper::getAttachment))
+            .map(Attachment::getBytes)
+            .collect(ImmutableList.toImmutableList());
+
+        ImmutableList<byte[]> files = Stream.of("eml/4037_014.jpg", "eml/4037_015.jpg")
+                .map(ClassLoader::getSystemResourceAsStream)
+                .map(Throwing.function(IOUtils::toByteArray))
+                .collect(ImmutableList.toImmutableList());
+
+        assertThat(attachmentContents)
+            .containsExactlyInAnyOrder(files.get(0), files.get(1));
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/container/util/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/util/pom.xml b/server/container/util/pom.xml
index fa76097..85c3a6e 100644
--- a/server/container/util/pom.xml
+++ b/server/container/util/pom.xml
@@ -116,6 +116,12 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>backport-util-concurrent</groupId>
+            <artifactId>backport-util-concurrent</artifactId>
+            <version>3.1</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java b/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java
index bd1d177..830b01c 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/domainlist/cassandra/CassandraDomainList.java
@@ -112,7 +112,7 @@ public class CassandraDomainList extends AbstractDomainList {
     public void addDomain(Domain domain) throws DomainListException {
         boolean executed = executor.executeReturnApplied(insertStatement.bind()
             .setString(DOMAIN, domain.asString()))
-            .join();
+            .block();
         if (!executed) {
             throw new DomainListException(domain.name() + " already exists.");
         }
@@ -122,7 +122,7 @@ public class CassandraDomainList extends AbstractDomainList {
     public void removeDomain(Domain domain) throws DomainListException {
         boolean executed = executor.executeReturnApplied(removeStatement.bind()
             .setString(DOMAIN, domain.asString()))
-            .join();
+            .block();
         if (!executed) {
             throw new DomainListException(domain.name() + " was not found");
         }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
index 47c598d..10049e1 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
@@ -32,8 +32,6 @@ import static org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable.
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.util.Date;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
 
@@ -44,6 +42,7 @@ import org.apache.james.sieverepository.api.ScriptName;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
+import reactor.core.publisher.Mono;
 
 public class CassandraActiveScriptDAO {
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
@@ -66,23 +65,23 @@ public class CassandraActiveScriptDAO {
             .where(eq(USER_NAME, bindMarker(USER_NAME))));
     }
 
-    public CompletableFuture<Optional<ActiveScriptInfo>> getActiveSctiptInfo(User user) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    public Mono<ActiveScriptInfo> getActiveSctiptInfo(User user) {
+        return cassandraAsyncExecutor.executeSingleRowReactor(
             selectActiveName.bind()
                 .setString(USER_NAME, user.asString()))
-            .thenApply(rowOptional -> rowOptional.map(row -> new ActiveScriptInfo(
+            .map(row -> new ActiveScriptInfo(
                 new ScriptName(row.getString(SCRIPT_NAME)),
-                ZonedDateTime.ofInstant(row.getTimestamp(DATE).toInstant(), ZoneOffset.UTC))));
+                ZonedDateTime.ofInstant(row.getTimestamp(DATE).toInstant(), ZoneOffset.UTC)));
     }
 
-    public CompletableFuture<Void> unactivate(User user) {
-        return cassandraAsyncExecutor.executeVoid(
+    public Mono<Void> unactivate(User user) {
+        return cassandraAsyncExecutor.executeVoidReactor(
             deleteActive.bind()
                 .setString(USER_NAME, user.asString()));
     }
 
-    public CompletableFuture<Void> activate(User user, ScriptName scriptName) {
-        return cassandraAsyncExecutor.executeVoid(
+    public Mono<Void> activate(User user, ScriptName scriptName) {
+        return cassandraAsyncExecutor.executeVoidReactor(
             insertActive.bind()
                 .setString(USER_NAME, user.asString())
                 .setString(SCRIPT_NAME, scriptName.getValue())

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
index 429ca4b..d3cf741 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
@@ -34,7 +34,6 @@ import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.TABLE_
 import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.USER_NAME;
 
 import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 
 import javax.inject.Inject;
@@ -50,6 +49,7 @@ import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
 import com.datastax.driver.core.querybuilder.Select;
 import com.github.steveash.guavate.Guavate;
+import reactor.core.publisher.Mono;
 
 public class CassandraSieveDAO {
 
@@ -98,8 +98,8 @@ public class CassandraSieveDAO {
             .where(eq(USER_NAME, bindMarker(USER_NAME)));
     }
 
-    public CompletableFuture<Void> insertScript(User user, Script script) {
-        return cassandraAsyncExecutor.executeVoid(
+    public Mono<Void> insertScript(User user, Script script) {
+        return cassandraAsyncExecutor.executeVoidReactor(
             insertScriptStatement.bind()
                 .setString(USER_NAME, user.asString())
                 .setString(SCRIPT_NAME, script.getName().getValue())
@@ -120,7 +120,7 @@ public class CassandraSieveDAO {
                 .collect(Guavate.toImmutableList()));
     }
 
-    public CompletableFuture<Boolean> updateScriptActivation(User user, ScriptName scriptName, boolean active) {
+    public Mono<Boolean> updateScriptActivation(User user, ScriptName scriptName, boolean active) {
         return cassandraAsyncExecutor.executeReturnApplied(
             updateScriptActivationStatement.bind()
                 .setString(USER_NAME, user.asString())
@@ -128,24 +128,24 @@ public class CassandraSieveDAO {
                 .setBool(IS_ACTIVE, active));
     }
 
-    public CompletableFuture<Optional<Script>> getScript(User user, ScriptName name) {
-        return getScriptRow(user, name).thenApply(opt -> opt.map(row -> Script.builder()
+    public Mono<Script> getScript(User user, ScriptName name) {
+        return getScriptRow(user, name).map(row -> Script.builder()
                 .content(row.getString(SCRIPT_CONTENT))
                 .isActive(row.getBool(IS_ACTIVE))
                 .name(name)
                 .size(row.getLong(SIZE))
-                .build()));
+                .build());
     }
 
-    public CompletableFuture<Boolean> deleteScriptInCassandra(User user, ScriptName name) {
+    public Mono<Boolean> deleteScriptInCassandra(User user, ScriptName name) {
         return cassandraAsyncExecutor.executeReturnApplied(
             deleteScriptStatement.bind()
                 .setString(USER_NAME, user.asString())
                 .setString(SCRIPT_NAME, name.getValue()));
     }
 
-    private CompletableFuture<Optional<Row>> getScriptRow(User user, ScriptName name) {
-        return cassandraAsyncExecutor.executeSingleRow(
+    private Mono<Row> getScriptRow(User user, ScriptName name) {
+        return cassandraAsyncExecutor.executeSingleRowReactor(
             selectScriptStatement.bind()
                 .setString(USER_NAME, user.asString())
                 .setString(SCRIPT_NAME, name.getValue()));

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAO.java
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAO.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAO.java
index b20ea30..1e99f1a 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAO.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAO.java
@@ -41,6 +41,7 @@ import org.apache.james.sieve.cassandra.tables.CassandraSieveSpaceTable;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Session;
+import reactor.core.publisher.Mono;
 
 public class CassandraSieveQuotaDAO {
 
@@ -107,8 +108,8 @@ public class CassandraSieveQuotaDAO {
                 .orElse(0L));
     }
 
-    public CompletableFuture<Void> updateSpaceUsed(User user, long spaceUsed) {
-        return cassandraAsyncExecutor.executeVoid(
+    public Mono<Void> updateSpaceUsed(User user, long spaceUsed) {
+        return cassandraAsyncExecutor.executeVoidReactor(
             updateSpaceUsedStatement.bind()
                 .setLong(CassandraSieveSpaceTable.SPACE_USED, spaceUsed)
                 .setString(CassandraSieveSpaceTable.USER_NAME, user.asString()));

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
index fa52b4a..7f4b559 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
@@ -25,6 +25,7 @@ import java.time.ZonedDateTime;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
 
 import javax.inject.Inject;
 
@@ -43,7 +44,11 @@ import org.apache.james.sieverepository.api.exception.IsActiveException;
 import org.apache.james.sieverepository.api.exception.QuotaExceededException;
 import org.apache.james.sieverepository.api.exception.QuotaNotFoundException;
 import org.apache.james.sieverepository.api.exception.ScriptNotFoundException;
-import org.apache.james.util.CompletableFutureUtil;
+
+import org.apache.james.util.FunctionalUtils;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
 
 public class CassandraSieveRepository implements SieveRepository {
 
@@ -60,7 +65,8 @@ public class CassandraSieveRepository implements SieveRepository {
 
     @Override
     public ZonedDateTime getActivationDateForActiveScript(User user) throws ScriptNotFoundException {
-        return cassandraActiveScriptDAO.getActiveSctiptInfo(user).join()
+        return cassandraActiveScriptDAO.getActiveSctiptInfo(user)
+            .blockOptional()
             .orElseThrow(ScriptNotFoundException::new)
             .getActivationDate();
     }
@@ -70,19 +76,20 @@ public class CassandraSieveRepository implements SieveRepository {
         throwOnOverQuota(user, spaceThatWillBeUsedByNewScript(user, name, newSize));
     }
 
-    private void throwOnOverQuota(User user, CompletableFuture<Long> sizeDifference) throws QuotaExceededException {
+    private void throwOnOverQuota(User user, Mono<Long> sizeDifference) throws QuotaExceededException {
         CompletableFuture<Optional<QuotaSize>> userQuotaFuture = cassandraSieveQuotaDAO.getQuota(user);
         CompletableFuture<Optional<QuotaSize>> globalQuotaFuture = cassandraSieveQuotaDAO.getQuota();
         CompletableFuture<Long> spaceUsedFuture = cassandraSieveQuotaDAO.spaceUsedBy(user);
 
         new SieveQuota(spaceUsedFuture.join(), limitToUse(userQuotaFuture, globalQuotaFuture))
-            .checkOverQuotaUponModification(sizeDifference.join());
+            .checkOverQuotaUponModification(sizeDifference.block());
     }
 
-    private CompletableFuture<Long> spaceThatWillBeUsedByNewScript(User user, ScriptName name, long scriptSize) {
+    private Mono<Long> spaceThatWillBeUsedByNewScript(User user, ScriptName name, long scriptSize) {
         return cassandraSieveDAO.getScript(user, name)
-            .thenApply(optional -> optional.map(Script::getSize).orElse(0L))
-            .thenApply(sizeOfStoredScript -> scriptSize - sizeOfStoredScript);
+            .map(Script::getSize)
+            .switchIfEmpty(Mono.just(0L))
+            .map(sizeOfStoredScript -> scriptSize - sizeOfStoredScript);
     }
 
     private Optional<QuotaSize> limitToUse(CompletableFuture<Optional<QuotaSize>> userQuota, CompletableFuture<Optional<QuotaSize>> globalQuota) {
@@ -94,23 +101,24 @@ public class CassandraSieveRepository implements SieveRepository {
 
     @Override
     public void putScript(User user, ScriptName name, ScriptContent content) throws QuotaExceededException {
-        CompletableFuture<Long> spaceUsed = spaceThatWillBeUsedByNewScript(user, name, content.length());
+        Mono<Long> spaceUsed = spaceThatWillBeUsedByNewScript(user, name, content.length());
         throwOnOverQuota(user, spaceUsed);
 
-        CompletableFuture.allOf(
-            updateSpaceUsed(user, spaceUsed.join()),
+        Flux.merge(
+            updateSpaceUsed(user, spaceUsed.block()),
             cassandraSieveDAO.insertScript(user,
                 Script.builder()
                     .name(name)
                     .content(content)
                     .isActive(false)
                     .build()))
-            .join();
+            .then()
+            .block();
     }
 
-    private CompletableFuture<Void> updateSpaceUsed(User user, long spaceUsed) {
+    private Mono<Void> updateSpaceUsed(User user, long spaceUsed) {
         if (spaceUsed == 0) {
-            return CompletableFuture.completedFuture(null);
+            return Mono.empty();
         }
         return cassandraSieveQuotaDAO.updateSpaceUsed(user, spaceUsed);
     }
@@ -124,10 +132,8 @@ public class CassandraSieveRepository implements SieveRepository {
     public InputStream getActive(User user) throws ScriptNotFoundException {
         return IOUtils.toInputStream(
             cassandraActiveScriptDAO.getActiveSctiptInfo(user)
-                .thenCompose(optionalActiveName -> optionalActiveName
-                    .map(activeScriptInfo -> cassandraSieveDAO.getScript(user, activeScriptInfo.getName()))
-                    .orElse(CompletableFuture.completedFuture(Optional.empty())))
-                .join()
+                .flatMap(activeScriptInfo -> cassandraSieveDAO.getScript(user, activeScriptInfo.getName()))
+                .blockOptional()
                 .orElseThrow(ScriptNotFoundException::new)
                 .getContent()
                 .getValue(), StandardCharsets.UTF_8);
@@ -135,36 +141,33 @@ public class CassandraSieveRepository implements SieveRepository {
 
     @Override
     public void setActive(User user, ScriptName name) throws ScriptNotFoundException {
-        CompletableFuture<Boolean> activateNewScript =
+        Mono<Boolean> activateNewScript =
             unactivateOldScript(user)
-                .thenCompose(any -> updateScriptActivation(user, name, true)
-                    .thenCompose(CompletableFutureUtil.composeIfTrue(
-                        () -> cassandraActiveScriptDAO.activate(user, name))));
+                .then(updateScriptActivation(user, name, true))
+                .filter(FunctionalUtils.toPredicate(Function.identity()))
+                .flatMap(any -> cassandraActiveScriptDAO.activate(user, name).thenReturn(any));
 
-        if (!activateNewScript.join()) {
+        if (!activateNewScript.blockOptional().isPresent()) {
             throw new ScriptNotFoundException();
         }
     }
 
-    private CompletableFuture<Void> unactivateOldScript(User user) {
+    private Mono<Void> unactivateOldScript(User user) {
         return cassandraActiveScriptDAO.getActiveSctiptInfo(user)
-            .thenCompose(scriptNameOptional -> scriptNameOptional
-                .map(activeScriptInfo -> updateScriptActivation(user, activeScriptInfo.getName(), false)
-                    .<Void>thenApply(any -> null))
-                .orElse(CompletableFuture.completedFuture(null)));
+            .flatMap(activeScriptInfo -> updateScriptActivation(user, activeScriptInfo.getName(), false).then());
     }
 
-    private CompletableFuture<Boolean> updateScriptActivation(User user, ScriptName scriptName, boolean active) {
+    private Mono<Boolean> updateScriptActivation(User user, ScriptName scriptName, boolean active) {
         if (!scriptName.equals(SieveRepository.NO_SCRIPT_NAME)) {
             return cassandraSieveDAO.updateScriptActivation(user, scriptName, active);
         }
-        return cassandraActiveScriptDAO.unactivate(user).thenApply(any -> true);
+        return cassandraActiveScriptDAO.unactivate(user).thenReturn(true);
     }
 
     @Override
     public InputStream getScript(User user, ScriptName name) throws ScriptNotFoundException {
         return  cassandraSieveDAO.getScript(user, name)
-            .join()
+            .blockOptional()
             .map(script -> IOUtils.toInputStream(script.getContent().getValue(), StandardCharsets.UTF_8))
             .orElseThrow(ScriptNotFoundException::new);
     }
@@ -172,13 +175,13 @@ public class CassandraSieveRepository implements SieveRepository {
     @Override
     public void deleteScript(User user, ScriptName name) throws ScriptNotFoundException, IsActiveException {
         ensureIsNotActive(user, name);
-        if (!cassandraSieveDAO.deleteScriptInCassandra(user, name).join()) {
+        if (!cassandraSieveDAO.deleteScriptInCassandra(user, name).switchIfEmpty(Mono.just(false)).block()) {
             throw new ScriptNotFoundException();
         }
     }
 
     private void ensureIsNotActive(User user, ScriptName name) throws IsActiveException {
-        Optional<ScriptName> activeName = cassandraActiveScriptDAO.getActiveSctiptInfo(user).join().map(ActiveScriptInfo::getName);
+        Optional<ScriptName> activeName = cassandraActiveScriptDAO.getActiveSctiptInfo(user).blockOptional().map(ActiveScriptInfo::getName);
         if (activeName.isPresent() && name.equals(activeName.get())) {
             throw new IsActiveException();
         }
@@ -186,22 +189,21 @@ public class CassandraSieveRepository implements SieveRepository {
 
     @Override
     public void renameScript(User user, ScriptName oldName, ScriptName newName) throws ScriptNotFoundException, DuplicateException {
-        CompletableFuture<Boolean> scriptExistsFuture = cassandraSieveDAO.getScript(user, newName)
-            .thenApply(Optional::isPresent);
-        CompletableFuture<Optional<Script>> oldScriptFuture = cassandraSieveDAO.getScript(user, oldName);
+        Mono<Script> oldScript = cassandraSieveDAO.getScript(user, oldName).cache();
+        Mono<Boolean> newScriptExists = cassandraSieveDAO.getScript(user, newName).hasElement();
 
-        oldScriptFuture.join();
-        if (scriptExistsFuture.join()) {
+        oldScript.block();
+        if (newScriptExists.block()) {
             throw new DuplicateException();
         }
 
         performScriptRename(user,
             newName,
-            oldScriptFuture.join().orElseThrow(ScriptNotFoundException::new));
+            oldScript.blockOptional().orElseThrow(ScriptNotFoundException::new));
     }
 
     private void performScriptRename(User user, ScriptName newName, Script oldScript) {
-        CompletableFuture.allOf(
+        Flux.merge(
             cassandraSieveDAO.insertScript(user,
                 Script.builder()
                     .copyOf(oldScript)
@@ -209,15 +211,14 @@ public class CassandraSieveRepository implements SieveRepository {
                     .build()),
             cassandraSieveDAO.deleteScriptInCassandra(user, oldScript.getName()),
             performActiveScriptRename(user, oldScript.getName(), newName))
-            .join();
+            .then()
+            .block();
     }
 
-    private CompletableFuture<Void> performActiveScriptRename(User user, ScriptName oldName, ScriptName newName) {
+    private Mono<Void> performActiveScriptRename(User user, ScriptName oldName, ScriptName newName) {
         return cassandraActiveScriptDAO.getActiveSctiptInfo(user)
-            .thenCompose(optionalActivationInfo -> optionalActivationInfo
-                .filter(activeScriptInfo -> activeScriptInfo.getName().equals(oldName))
-                .map(name -> cassandraActiveScriptDAO.activate(user, newName))
-                .orElse(CompletableFuture.completedFuture(null)));
+            .filter(activeScriptInfo -> activeScriptInfo.getName().equals(oldName))
+            .flatMap(name -> cassandraActiveScriptDAO.activate(user, newName));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4a737e5/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
----------------------------------------------------------------------
diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
index 45504ab..0d6eee8 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
@@ -137,7 +137,7 @@ public class CassandraUsersRepository extends AbstractUsersRepository {
                     .setString(PASSWORD, defaultUser.getHashedPassword())
                     .setString(ALGORITHM, defaultUser.getHashAlgorithm())
                     .setString(NAME, defaultUser.getUserName().toLowerCase(Locale.US)))
-            .join();
+            .block();
 
         if (!executed) {
             throw new UsersRepositoryException("Unable to update user");
@@ -149,7 +149,7 @@ public class CassandraUsersRepository extends AbstractUsersRepository {
         boolean executed = executor.executeReturnApplied(
             removeUserStatement.bind()
                 .setString(NAME, name))
-            .join();
+            .block();
 
         if (!executed) {
             throw new UsersRepositoryException("unable to remove unknown user " + name);
@@ -202,7 +202,7 @@ public class CassandraUsersRepository extends AbstractUsersRepository {
                 .setString(REALNAME, user.getUserName())
                 .setString(PASSWORD, user.getHashedPassword())
                 .setString(ALGORITHM, user.getHashAlgorithm()))
-            .join();
+            .block();
 
         if (!executed) {
             throw new AlreadyExistInUsersRepositoryException("User with username " + username + " already exist!");


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