You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/05/14 06:42:36 UTC

[james-project] 04/15: [REFACTORING] Fasten Mailbox/get & Email/query with reactive MailboxManager::getMailbox

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

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

commit 2bc8a96582ef1447dd630fafc4fa6b09007c7e82
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri May 7 18:12:28 2021 +0700

    [REFACTORING] Fasten Mailbox/get & Email/query with reactive MailboxManager::getMailbox
---
 .../org/apache/james/mailbox/MailboxManager.java   |   4 +
 .../quota/InMemoryCurrentQuotaManager.java         |  14 +--
 .../james/mailbox/store/StoreMailboxManager.java   |  54 +++++---
 .../jmap/draft/methods/GetMailboxesMethod.java     |  18 +--
 .../jmap/draft/methods/GetMessageListMethod.java   |   9 +-
 .../methods/SetMailboxesCreationProcessor.java     |   3 +-
 .../methods/SetMailboxesDestructionProcessor.java  |   3 +-
 .../draft/methods/SetMailboxesUpdateProcessor.java |   1 +
 .../james/jmap/draft/model/MailboxFactory.java     | 138 +++++++++++----------
 .../methods/SetMailboxesUpdateProcessorTest.java   |   4 +-
 .../james/jmap/draft/model/MailboxFactoryTest.java |  31 ++---
 .../james/jmap/method/EmailQueryMethod.scala       |   6 +-
 .../data/jmap/EmailQueryViewPopulator.java         |   3 +-
 .../jmap/MessageFastViewProjectionCorrector.java   |   3 +-
 14 files changed, 154 insertions(+), 137 deletions(-)

diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java
index a175127..6ee804b 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java
@@ -139,6 +139,10 @@ public interface MailboxManager extends RequestAware, RightManager, MailboxAnnot
      */
     MessageManager getMailbox(MailboxId mailboxId, MailboxSession session) throws MailboxException;
 
+    Publisher<MessageManager> getMailboxReactive(MailboxId mailboxId, MailboxSession session);
+
+    Publisher<MessageManager> getMailboxReactive(MailboxPath mailboxPath, MailboxSession session);
+
     /**
      * Creates a new mailbox. Any intermediary mailboxes missing from the
      * hierarchy should be created.
diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/quota/InMemoryCurrentQuotaManager.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/quota/InMemoryCurrentQuotaManager.java
index 120df80..26b35dc 100644
--- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/quota/InMemoryCurrentQuotaManager.java
+++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/quota/InMemoryCurrentQuotaManager.java
@@ -60,7 +60,6 @@ public class InMemoryCurrentQuotaManager implements CurrentQuotaManager {
 
     public CurrentQuotas loadQuotas(QuotaRoot quotaRoot, CurrentQuotaCalculator quotaCalculator, SessionProvider sessionProvider) {
         return quotaCalculator.recalculateCurrentQuotas(quotaRoot, sessionProvider.createSystemSession(Username.of(quotaRoot.getValue())))
-            .subscribeOn(Schedulers.elastic())
             .block();
     }
 
@@ -77,22 +76,20 @@ public class InMemoryCurrentQuotaManager implements CurrentQuotaManager {
     @Override
     public Mono<QuotaCountUsage> getCurrentMessageCount(QuotaRoot quotaRoot) {
         return Mono.fromCallable(() -> quotaCache.get(quotaRoot).get().count())
-            .onErrorMap(this::wrapAsMailboxException)
-            .subscribeOn(Schedulers.elastic());
+            .onErrorMap(this::wrapAsMailboxException);
     }
 
     @Override
     public Mono<QuotaSizeUsage> getCurrentStorage(QuotaRoot quotaRoot) {
         return Mono.fromCallable(() -> quotaCache.get(quotaRoot).get().size())
-            .onErrorMap(this::wrapAsMailboxException)
-            .subscribeOn(Schedulers.elastic());
+            .onErrorMap(this::wrapAsMailboxException);
     }
 
     @Override
     public Mono<CurrentQuotas> getCurrentQuotas(QuotaRoot quotaRoot) {
         return Mono.fromCallable(() -> quotaCache.get(quotaRoot).get())
-            .onErrorMap(this::wrapAsMailboxException)
-            .subscribeOn(Schedulers.elastic());
+            .subscribeOn(Schedulers.elastic())
+            .onErrorMap(this::wrapAsMailboxException);
     }
 
     @Override
@@ -100,8 +97,7 @@ public class InMemoryCurrentQuotaManager implements CurrentQuotaManager {
         return getCurrentQuotas(quotaOperation.quotaRoot())
             .filter(Predicate.not(Predicate.isEqual(CurrentQuotas.from(quotaOperation))))
             .flatMap(storedQuotas -> decrease(new QuotaOperation(quotaOperation.quotaRoot(), storedQuotas.count(), storedQuotas.size()))
-                .then(increase(quotaOperation)))
-            .subscribeOn(Schedulers.elastic());
+                .then(increase(quotaOperation)));
     }
 
     private Mono<Void> updateQuota(QuotaRoot quotaRoot, UnaryOperator<CurrentQuotas> quotaFunction) {
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
index ceabd4d..6837272 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
@@ -87,6 +87,7 @@ import org.apache.james.mailbox.store.search.MessageSearchIndex;
 import org.apache.james.mailbox.store.user.SubscriptionMapper;
 import org.apache.james.mailbox.store.user.model.Subscription;
 import org.apache.james.util.FunctionalUtils;
+import org.reactivestreams.Publisher;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -265,37 +266,50 @@ public class StoreMailboxManager implements MailboxManager {
 
     @Override
     public MessageManager getMailbox(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
-        final MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-        Mailbox mailboxRow = mapper.findMailboxByPath(mailboxPath)
-            .blockOptional()
-            .orElseThrow(() -> {
-                LOGGER.info("Mailbox '{}' not found.", mailboxPath);
-                return new MailboxNotFoundException(mailboxPath);
-            });
+        return MailboxReactorUtils.block(getMailboxReactive(mailboxPath, session));
+    }
 
-        if (!assertUserHasAccessTo(mailboxRow, session)) {
-            LOGGER.info("Mailbox '{}' does not belong to user '{}' but to '{}'", mailboxPath, session.getUser(), mailboxRow.getUser());
-            throw new MailboxNotFoundException(mailboxPath);
-        }
+    @Override
+    public Mono<MessageManager> getMailboxReactive(MailboxPath mailboxPath, MailboxSession session) {
+        MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
+
+        return mapper.findMailboxByPath(mailboxPath)
+            .map(Throwing.<Mailbox, MessageManager>function(mailboxRow -> {
+                if (!assertUserHasAccessTo(mailboxRow, session)) {
+                    LOGGER.info("Mailbox '{}' does not belong to user '{}' but to '{}'", mailboxPath, session.getUser(), mailboxRow.getUser());
+                    throw new MailboxNotFoundException(mailboxPath);
+                }
 
-        LOGGER.debug("Loaded mailbox {}", mailboxPath);
+                LOGGER.debug("Loaded mailbox {}", mailboxPath);
 
-        return createMessageManager(mailboxRow, session);
+                return createMessageManager(mailboxRow, session);
+            }).sneakyThrow())
+            .switchIfEmpty(Mono.fromCallable(() -> {
+                LOGGER.info("Mailbox '{}' not found.", mailboxPath);
+                throw new MailboxNotFoundException(mailboxPath);
+            }));
     }
 
     @Override
     public MessageManager getMailbox(MailboxId mailboxId, MailboxSession session) throws MailboxException {
+        return block(getMailboxReactive(mailboxId, session));
+    }
+
+    @Override
+    public Publisher<MessageManager> getMailboxReactive(MailboxId mailboxId, MailboxSession session) {
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-        Mailbox mailboxRow = block(mapper.findMailboxById(mailboxId));
 
-        if (!assertUserHasAccessTo(mailboxRow, session)) {
-            LOGGER.info("Mailbox '{}' does not belong to user '{}' but to '{}'", mailboxId.serialize(), session.getUser(), mailboxRow.getUser());
-            throw new MailboxNotFoundException(mailboxId);
-        }
+        return mapper.findMailboxById(mailboxId)
+            .map(Throwing.<Mailbox, MessageManager>function(mailboxRow -> {
+                if (!assertUserHasAccessTo(mailboxRow, session)) {
+                    LOGGER.info("Mailbox '{} {}' does not belong to user '{}' but to '{}'", mailboxRow.getMailboxId().serialize(), mailboxRow.generateAssociatedPath(), session.getUser(), mailboxRow.getUser());
+                    throw new MailboxNotFoundException(mailboxId);
+                }
 
-        LOGGER.debug("Loaded mailbox {}", mailboxId.serialize());
+                LOGGER.debug("Loaded mailbox {} {}", mailboxRow.getMailboxId().serialize(), mailboxRow.generateAssociatedPath());
 
-        return createMessageManager(mailboxRow, session);
+                return createMessageManager(mailboxRow, session);
+            }).sneakyThrow());
     }
 
     private boolean assertUserHasAccessTo(Mailbox mailbox, MailboxSession session) {
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMailboxesMethod.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMailboxesMethod.java
index 610924f..8381fdc 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMailboxesMethod.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMailboxesMethod.java
@@ -21,7 +21,6 @@ package org.apache.james.jmap.draft.methods;
 
 import static org.apache.james.util.ReactorUtils.DEFAULT_CONCURRENCY;
 import static org.apache.james.util.ReactorUtils.context;
-import static org.apache.james.util.ReactorUtils.publishIfPresent;
 
 import java.util.Comparator;
 import java.util.List;
@@ -57,7 +56,6 @@ import com.google.common.collect.Sets;
 
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
 
 public class GetMailboxesMethod implements Method {
 
@@ -143,32 +141,26 @@ public class GetMailboxesMethod implements Method {
 
     private Flux<Mailbox> retrieveSpecificMailboxes(MailboxSession mailboxSession, ImmutableList<MailboxId> mailboxIds) {
         return Flux.fromIterable(mailboxIds)
-            .flatMap(mailboxId -> Mono.fromCallable(() ->
-                mailboxFactory.builder()
+            .flatMap(mailboxId -> mailboxFactory.builder()
                     .id(mailboxId)
                     .session(mailboxSession)
                     .usingPreloadedMailboxesMetadata(NO_PRELOADED_METADATA)
-                    .build())
-                .subscribeOn(Schedulers.elastic()), DEFAULT_CONCURRENCY)
-            .handle(publishIfPresent());
+                    .build(), DEFAULT_CONCURRENCY);
     }
 
     private Flux<Mailbox> retrieveAllMailboxes(MailboxSession mailboxSession) {
         Mono<List<MailboxMetaData>> userMailboxesMono = getAllMailboxesMetaData(mailboxSession).collectList();
-        Mono<QuotaLoaderWithDefaultPreloaded> quotaLoaderMono = Mono.fromCallable(() ->
-            new QuotaLoaderWithDefaultPreloaded(quotaRootResolver, quotaManager, mailboxSession))
-            .subscribeOn(Schedulers.elastic());
+        Mono<QuotaLoaderWithDefaultPreloaded> quotaLoaderMono = QuotaLoaderWithDefaultPreloaded.preLoad(quotaRootResolver, quotaManager, mailboxSession);
 
         return userMailboxesMono.zipWith(quotaLoaderMono)
             .flatMapMany(
                 tuple -> Flux.fromIterable(tuple.getT1())
-                    .map(mailboxMetaData -> mailboxFactory.builder()
+                    .flatMap(mailboxMetaData -> mailboxFactory.builder()
                         .mailboxMetadata(mailboxMetaData)
                         .session(mailboxSession)
                         .usingPreloadedMailboxesMetadata(Optional.of(tuple.getT1()))
                         .quotaLoader(tuple.getT2())
-                        .build())
-                    .handle(publishIfPresent()));
+                        .build()));
     }
 
     private Flux<MailboxMetaData> getAllMailboxesMetaData(MailboxSession mailboxSession) {
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java
index 69d64d5e..caad396 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/GetMessageListMethod.java
@@ -115,8 +115,7 @@ public class GetMessageListMethod implements Method {
 
         return metricFactory.decorateSupplierWithTimerMetricLogP99(JMAP_PREFIX + METHOD_NAME.getName(),
             () -> process(methodCallId, mailboxSession, messageListRequest)
-                .subscriberContext(context("GET_MESSAGE_LIST", mdc(messageListRequest))))
-            .subscribeOn(Schedulers.elastic());
+                .subscriberContext(context("GET_MESSAGE_LIST", mdc(messageListRequest))));
     }
 
     private MDCBuilder mdc(GetMessageListRequest messageListRequest) {
@@ -171,8 +170,7 @@ public class GetMessageListMethod implements Method {
             MailboxId mailboxId = mailboxIdFactory.fromString(mailboxIdAsString);
             Limit aLimit = Limit.from(Math.toIntExact(limit));
 
-            return Mono.fromCallable(() -> mailboxManager.getMailbox(mailboxId, mailboxSession))
-                .subscribeOn(Schedulers.elastic())
+            return Mono.from(mailboxManager.getMailboxReactive(mailboxId, mailboxSession))
                 .then(emailQueryView.listMailboxContent(mailboxId, aLimit)
                     .skip(position)
                     .take(limit)
@@ -188,8 +186,7 @@ public class GetMessageListMethod implements Method {
             ZonedDateTime after = condition.getAfter().get();
             Limit aLimit = Limit.from(Math.toIntExact(limit));
 
-            return Mono.fromCallable(() -> mailboxManager.getMailbox(mailboxId, mailboxSession))
-                .subscribeOn(Schedulers.elastic())
+            return Mono.from(mailboxManager.getMailboxReactive(mailboxId, mailboxSession))
                 .then(emailQueryView.listMailboxContentSinceReceivedAt(mailboxId, after, aLimit)
                     .skip(position)
                     .take(limit)
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesCreationProcessor.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesCreationProcessor.java
index c75b462..25a1a69 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesCreationProcessor.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesCreationProcessor.java
@@ -121,7 +121,8 @@ public class SetMailboxesCreationProcessor implements SetMailboxesProcessor {
             Optional<Mailbox> mailbox = mailboxId.flatMap(id -> mailboxFactory.builder()
                     .id(id)
                     .session(mailboxSession)
-                    .build());
+                    .build()
+                    .blockOptional());
             if (mailbox.isPresent()) {
                 subscriptionManager.subscribe(mailboxSession, mailboxPath.getName());
                 builder.created(mailboxCreationId, mailbox.get());
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesDestructionProcessor.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesDestructionProcessor.java
index 1238147..dbd2e1e 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesDestructionProcessor.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesDestructionProcessor.java
@@ -98,7 +98,8 @@ public class SetMailboxesDestructionProcessor implements SetMailboxesProcessor {
             .map(id -> mailboxFactory.builder()
                     .id(id)
                     .session(mailboxSession)
-                    .build())
+                    .build()
+                    .blockOptional())
             .flatMap(Optional::stream)
             .forEach(mailbox -> idToMailboxBuilder.put(mailbox.getId(), mailbox));
         return idToMailboxBuilder.build();
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessor.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessor.java
index acf2747..33aa98e 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessor.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessor.java
@@ -181,6 +181,7 @@ public class SetMailboxesUpdateProcessor implements SetMailboxesProcessor {
                 .id(mailboxId)
                 .session(mailboxSession)
                 .build()
+                .blockOptional()
                 .orElseThrow(() -> new MailboxNotFoundException(mailboxId));
     }
 
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/MailboxFactory.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/MailboxFactory.java
index d4597b7..7f3f723 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/MailboxFactory.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/MailboxFactory.java
@@ -26,7 +26,6 @@ import javax.inject.Inject;
 import org.apache.james.core.Username;
 import org.apache.james.jmap.draft.model.mailbox.Mailbox;
 import org.apache.james.jmap.draft.model.mailbox.MailboxNamespace;
-import org.apache.james.jmap.draft.model.mailbox.Quotas;
 import org.apache.james.jmap.draft.model.mailbox.Rights;
 import org.apache.james.jmap.draft.model.mailbox.SortOrder;
 import org.apache.james.jmap.draft.utils.quotas.DefaultQuotaLoader;
@@ -35,7 +34,6 @@ import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.Role;
-import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxCounters;
@@ -52,8 +50,31 @@ import com.google.common.base.Splitter;
 import com.google.common.primitives.Booleans;
 
 import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
 
 public class MailboxFactory {
+    private static class MailboxTuple {
+        public static MailboxTuple from(MailboxMetaData metaData) {
+            return new MailboxTuple(metaData.getPath(), metaData.getCounters().sanitize(), metaData.getResolvedAcls());
+        }
+
+        public static Mono<MailboxTuple> from(MessageManager messageManager, MailboxSession session) {
+            return Mono.fromCallable(() ->
+                new MailboxTuple(messageManager.getMailboxPath(), messageManager.getMailboxCounters(session).sanitize(), messageManager.getResolvedAcl(session)))
+                .subscribeOn(Schedulers.elastic());
+        }
+
+        private final MailboxPath mailboxPath;
+        private final MailboxCounters.Sanitized mailboxCounters;
+        private final MailboxACL acl;
+
+        private MailboxTuple(MailboxPath mailboxPath, MailboxCounters.Sanitized mailboxCounters, MailboxACL acl) {
+            this.mailboxPath = mailboxPath;
+            this.mailboxCounters = mailboxCounters;
+            this.acl = acl;
+        }
+    }
+
     private final MailboxManager mailboxManager;
     private final QuotaManager quotaManager;
     private final QuotaRootResolver quotaRootResolver;
@@ -96,36 +117,25 @@ public class MailboxFactory {
             return this;
         }
 
-        public Optional<Mailbox> build() {
+        public Mono<Mailbox> build() {
             Preconditions.checkNotNull(session);
 
-            try {
-                MailboxId mailboxId = computeMailboxId();
-                Mono<MessageManager> mailbox = mailbox(mailboxId).cache();
-
-                MailboxACL mailboxACL = mailboxMetaData.map(MailboxMetaData::getResolvedAcls)
-                    .orElseGet(Throwing.supplier(() -> retrieveCachedMailbox(mailboxId, mailbox).getResolvedAcl(session)).sneakyThrow());
-
-                MailboxPath mailboxPath = mailboxMetaData.map(MailboxMetaData::getPath)
-                    .orElseGet(Throwing.supplier(() -> retrieveCachedMailbox(mailboxId, mailbox).getMailboxPath()).sneakyThrow());
-
-                MailboxCounters.Sanitized mailboxCounters = mailboxMetaData.map(MailboxMetaData::getCounters)
-                    .orElseGet(Throwing.supplier(() -> retrieveCachedMailbox(mailboxId, mailbox).getMailboxCounters(session)).sneakyThrow())
-                    .sanitize();
-
-                return Optional.of(mailboxFactory.from(
-                    mailboxId,
-                    mailboxPath,
-                    mailboxCounters,
-                    mailboxACL,
-                    userMailboxesMetadata,
-                    quotaLoader,
-                    session));
-            } catch (MailboxNotFoundException e) {
-                return Optional.empty();
-            } catch (MailboxException e) {
-                throw new RuntimeException(e);
-            }
+            MailboxId mailboxId = computeMailboxId();
+
+            Mono<MailboxTuple> mailbox = mailboxMetaData.map(MailboxTuple::from)
+                .map(Mono::just)
+                .orElse(Mono.from(mailboxFactory.mailboxManager.getMailboxReactive(mailboxId, session))
+                    .flatMap(messageManager -> MailboxTuple.from(messageManager, session)));
+
+            return mailbox.flatMap(tuple -> mailboxFactory.from(
+                mailboxId,
+                tuple.mailboxPath,
+                tuple.mailboxCounters,
+                tuple.acl,
+                userMailboxesMetadata,
+                quotaLoader,
+                session))
+                .onErrorResume(MailboxNotFoundException.class, e -> Mono.empty());
         }
 
         private MailboxId computeMailboxId() {
@@ -137,14 +147,13 @@ public class MailboxFactory {
         }
 
         private Mono<MessageManager> mailbox(MailboxId mailboxId) {
-            return Mono.fromCallable(() -> mailboxFactory.mailboxManager.getMailbox(mailboxId, session));
+            return Mono.from(mailboxFactory.mailboxManager.getMailboxReactive(mailboxId, session));
         }
 
-        private MessageManager retrieveCachedMailbox(MailboxId mailboxId, Mono<MessageManager> mailbox) throws MailboxNotFoundException {
+        private Mono<MessageManager> retrieveCachedMailbox(MailboxId mailboxId, Mono<MessageManager> mailbox) throws MailboxNotFoundException {
             return mailbox
                 .onErrorResume(MailboxNotFoundException.class, any -> Mono.empty())
-                .blockOptional()
-                .orElseThrow(() -> new MailboxNotFoundException(mailboxId));
+                .switchIfEmpty(Mono.error(() -> new MailboxNotFoundException(mailboxId)));
         }
     }
 
@@ -160,13 +169,13 @@ public class MailboxFactory {
         return new MailboxBuilder(this, defaultQuotaLoader);
     }
 
-    private Mailbox from(MailboxId mailboxId,
+    private Mono<Mailbox> from(MailboxId mailboxId,
                          MailboxPath mailboxPath,
                          MailboxCounters.Sanitized mailboxCounters,
                          MailboxACL resolvedAcl,
                          Optional<List<MailboxMetaData>> userMailboxesMetadata,
                          QuotaLoader quotaLoader,
-                         MailboxSession mailboxSession) throws MailboxException {
+                         MailboxSession mailboxSession) {
         boolean isOwner = mailboxPath.belongsTo(mailboxSession);
         Optional<Role> role = Role.from(mailboxPath.getName())
             .filter(any -> mailboxPath.belongsTo(mailboxSession));
@@ -175,26 +184,27 @@ public class MailboxFactory {
             .removeEntriesFor(mailboxPath.getUser());
         Username username = mailboxSession.getUser();
 
-        Quotas quotas = quotaLoader.getQuotas(mailboxPath);
-
-        return Mailbox.builder()
-            .id(mailboxId)
-            .name(getName(mailboxPath, mailboxSession))
-            .parentId(getParentIdFromMailboxPath(mailboxPath, userMailboxesMetadata, mailboxSession).orElse(null))
-            .role(role)
-            .unreadMessages(mailboxCounters.getUnseen())
-            .totalMessages(mailboxCounters.getCount())
-            .sortOrder(SortOrder.getSortOrder(role))
-            .sharedWith(rights)
-            .mayAddItems(rights.mayAddItems(username).orElse(isOwner))
-            .mayCreateChild(rights.mayCreateChild(username).orElse(isOwner))
-            .mayDelete(rights.mayDelete(username).orElse(isOwner))
-            .mayReadItems(rights.mayReadItems(username).orElse(isOwner))
-            .mayRemoveItems(rights.mayRemoveItems(username).orElse(isOwner))
-            .mayRename(rights.mayRename(username).orElse(isOwner))
-            .namespace(getNamespace(mailboxPath, isOwner))
-            .quotas(quotas)
-            .build();
+        return Mono.zip(
+                quotaLoader.getQuotas(mailboxPath),
+                getParentIdFromMailboxPath(mailboxPath, userMailboxesMetadata, mailboxSession))
+            .map(tuple -> Mailbox.builder()
+                .id(mailboxId)
+                .name(getName(mailboxPath, mailboxSession))
+                .parentId(tuple.getT2().orElse(null))
+                .role(role)
+                .unreadMessages(mailboxCounters.getUnseen())
+                .totalMessages(mailboxCounters.getCount())
+                .sortOrder(SortOrder.getSortOrder(role))
+                .sharedWith(rights)
+                .mayAddItems(rights.mayAddItems(username).orElse(isOwner))
+                .mayCreateChild(rights.mayCreateChild(username).orElse(isOwner))
+                .mayDelete(rights.mayDelete(username).orElse(isOwner))
+                .mayReadItems(rights.mayReadItems(username).orElse(isOwner))
+                .mayRemoveItems(rights.mayRemoveItems(username).orElse(isOwner))
+                .mayRename(rights.mayRename(username).orElse(isOwner))
+                .namespace(getNamespace(mailboxPath, isOwner))
+                .quotas(tuple.getT1())
+                .build());
     }
 
     private MailboxNamespace getNamespace(MailboxPath mailboxPath, boolean isOwner) {
@@ -215,21 +225,21 @@ public class MailboxFactory {
     }
 
     @VisibleForTesting
-    Optional<MailboxId> getParentIdFromMailboxPath(MailboxPath mailboxPath, Optional<List<MailboxMetaData>> userMailboxesMetadata,
-                                                   MailboxSession mailboxSession) throws MailboxException {
+    Mono<Optional<MailboxId>> getParentIdFromMailboxPath(MailboxPath mailboxPath, Optional<List<MailboxMetaData>> userMailboxesMetadata,
+                                                   MailboxSession mailboxSession) {
         List<MailboxPath> levels = mailboxPath.getHierarchyLevels(mailboxSession.getPathDelimiter());
         if (levels.size() <= 1) {
-            return Optional.empty();
+            return Mono.just(Optional.empty());
         }
         MailboxPath parent = levels.get(levels.size() - 2);
-        return userMailboxesMetadata.map(list -> retrieveParentFromMetadata(parent, list))
+        return userMailboxesMetadata.map(list -> Mono.just(retrieveParentFromMetadata(parent, list)))
             .orElseGet(Throwing.supplier(() -> retrieveParentFromBackend(mailboxSession, parent)).sneakyThrow());
     }
 
-    private Optional<MailboxId> retrieveParentFromBackend(MailboxSession mailboxSession, MailboxPath parent) throws MailboxException {
-        return Optional.of(
-            mailboxManager.getMailbox(parent, mailboxSession)
-                .getId());
+    private Mono<Optional<MailboxId>> retrieveParentFromBackend(MailboxSession mailboxSession, MailboxPath parent) {
+        return Mono.from(mailboxManager.getMailboxReactive(parent, mailboxSession))
+            .map(MessageManager::getId)
+            .map(Optional::of);
     }
 
     private Optional<MailboxId> retrieveParentFromMetadata(MailboxPath parent, List<MailboxMetaData> list) {
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessorTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessorTest.java
index 79859c4..7faa903 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessorTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessorTest.java
@@ -45,6 +45,8 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
 
+import reactor.core.publisher.Mono;
+
 public class SetMailboxesUpdateProcessorTest {
 
     private MailboxManager mockedMailboxManager;
@@ -79,7 +81,7 @@ public class SetMailboxesUpdateProcessorTest {
         when(mockBuilder.session(mockedMailboxSession))
             .thenReturn(mockBuilder);
         when(mockBuilder.build())
-            .thenReturn(Optional.of(mailbox));
+            .thenReturn(Mono.just(mailbox));
 
         when(mockedMailboxFactory.builder())
             .thenReturn(mockBuilder);
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/MailboxFactoryTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/MailboxFactoryTest.java
index 22e6c8f..e2ee241 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/MailboxFactoryTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/MailboxFactoryTest.java
@@ -82,7 +82,8 @@ public class MailboxFactoryTest {
         Optional<Mailbox> mailbox = sut.builder()
                 .id(InMemoryId.of(123))
                 .session(mailboxSession)
-                .build();
+                .build()
+                .blockOptional();
 
         assertThat(mailbox).isEmpty();
     }
@@ -96,7 +97,8 @@ public class MailboxFactoryTest {
         Optional<Mailbox> mailbox = sut.builder()
                 .id(mailboxId)
                 .session(mailboxSession)
-                .build();
+                .build()
+                .blockOptional();
 
         assertThat(mailbox).isPresent();
         assertThat(mailbox.get().getId()).isEqualTo(mailboxId);
@@ -134,7 +136,7 @@ public class MailboxFactoryTest {
         MailboxPath mailboxPath = MailboxPath.forUser(user, "mailbox");
         mailboxManager.createMailbox(mailboxPath, mailboxSession);
 
-        Optional<MailboxId> id = sut.getParentIdFromMailboxPath(mailboxPath, Optional.empty(), mailboxSession);
+        Optional<MailboxId> id = sut.getParentIdFromMailboxPath(mailboxPath, Optional.empty(), mailboxSession).block();
         assertThat(id).isEmpty();
     }
 
@@ -147,7 +149,7 @@ public class MailboxFactoryTest {
         MailboxPath mailboxPath = parentMailboxPath.child("mailbox", '.');
         mailboxManager.createMailbox(mailboxPath, mailboxSession);
 
-        Optional<MailboxId> id = sut.getParentIdFromMailboxPath(mailboxPath, Optional.empty(), mailboxSession);
+        Optional<MailboxId> id = sut.getParentIdFromMailboxPath(mailboxPath, Optional.empty(), mailboxSession).block();
         assertThat(id).contains(parentId);
     }
 
@@ -162,7 +164,7 @@ public class MailboxFactoryTest {
 
         mailboxManager.createMailbox(mailboxPath, mailboxSession);
 
-        Optional<MailboxId> id = sut.getParentIdFromMailboxPath(mailboxPath, Optional.empty(), mailboxSession);
+        Optional<MailboxId> id = sut.getParentIdFromMailboxPath(mailboxPath, Optional.empty(), mailboxSession).block();
         assertThat(id).contains(parentId);
     }
 
@@ -185,7 +187,7 @@ public class MailboxFactoryTest {
                     .count(0)
                     .unseen(0)
                     .build()))),
-            mailboxSession);
+            mailboxSession).block();
         assertThat(id).contains(parentId);
     }
 
@@ -198,7 +200,7 @@ public class MailboxFactoryTest {
             .id(mailboxId.get())
             .session(mailboxSession)
             .build()
-            .get();
+            .block();
 
         assertThat(retrievedMailbox.getNamespace())
             .isEqualTo(MailboxNamespace.personal());
@@ -227,7 +229,7 @@ public class MailboxFactoryTest {
                     .unseen(0)
                     .build()))))
             .build()
-            .get();
+            .block();
 
         assertThat(retrievedMailbox.getParentId())
             .contains(preLoadedId);
@@ -248,7 +250,7 @@ public class MailboxFactoryTest {
             .id(mailboxId.get())
             .session(otherMailboxSession)
             .build()
-            .get();
+            .block();
 
         assertThat(retrievedMailbox.getNamespace())
             .isEqualTo(MailboxNamespace.delegated(user));
@@ -263,7 +265,7 @@ public class MailboxFactoryTest {
             .id(mailboxId.get())
             .session(mailboxSession)
             .build()
-            .get();
+            .block();
 
         softly.assertThat(retrievedMailbox.isMayAddItems()).isTrue();
         softly.assertThat(retrievedMailbox.isMayCreateChild()).isTrue();
@@ -288,7 +290,7 @@ public class MailboxFactoryTest {
             .id(mailboxId.get())
             .session(otherMailboxSession)
             .build()
-            .get();
+            .block();
 
         softly.assertThat(retrievedMailbox.isMayAddItems()).isTrue();
         softly.assertThat(retrievedMailbox.isMayCreateChild()).isFalse();
@@ -313,7 +315,7 @@ public class MailboxFactoryTest {
             .id(mailboxId.get())
             .session(otherMailboxSession)
             .build()
-            .get();
+            .block();
 
         softly.assertThat(retrievedMailbox.isMayAddItems()).isFalse();
         softly.assertThat(retrievedMailbox.isMayCreateChild()).isFalse();
@@ -338,7 +340,7 @@ public class MailboxFactoryTest {
             .id(mailboxId.get())
             .session(otherMailboxSession)
             .build()
-            .get();
+            .block();
 
         softly.assertThat(retrievedMailbox.isMayAddItems()).isFalse();
         softly.assertThat(retrievedMailbox.isMayCreateChild()).isFalse();
@@ -367,7 +369,8 @@ public class MailboxFactoryTest {
         Optional<Mailbox> mailbox = sut.builder()
             .mailboxMetadata(metaData)
             .session(mailboxSession)
-            .build();
+            .build()
+            .blockOptional();
 
         softly.assertThat(mailbox).isPresent();
         softly.assertThat(mailbox).map(Mailbox::getId).contains(metaData.getId());
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
index ac2e32d..6f08d44 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala
@@ -107,8 +107,7 @@ class EmailQueryMethod @Inject() (serializer: EmailQuerySerializer,
     val condition: FilterCondition = request.filter.get.asInstanceOf[FilterCondition]
     val mailboxId: MailboxId = condition.inMailbox.get
     val after: ZonedDateTime = condition.after.get.asUTC
-    SMono.fromCallable(() => mailboxManager.getMailbox(mailboxId, mailboxSession))
-      .subscribeOn(Schedulers.elastic())
+    SMono(mailboxManager.getMailboxReactive(mailboxId, mailboxSession))
       .`then`(SFlux.fromPublisher(
         emailQueryView.listMailboxContentSinceReceivedAt(mailboxId, after, JavaLimit.from(limitToUse.value)))
         .drop(position.value)
@@ -122,8 +121,7 @@ class EmailQueryMethod @Inject() (serializer: EmailQuerySerializer,
 
   private def queryViewForListingSortedBySentAt(mailboxSession: MailboxSession, position: Position, limitToUse: Limit, request: EmailQueryRequest): SMono[Seq[MessageId]] = {
     val mailboxId: MailboxId = request.filter.get.asInstanceOf[FilterCondition].inMailbox.get
-    SMono.fromCallable(() => mailboxManager.getMailbox(mailboxId, mailboxSession))
-      .subscribeOn(Schedulers.elastic())
+    SMono(mailboxManager.getMailboxReactive(mailboxId, mailboxSession))
       .`then`(SFlux.fromPublisher(
         emailQueryView.listMailboxContent(mailboxId, JavaLimit.from(limitToUse.value)))
         .drop(position.value)
diff --git a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java
index 2ea9f16..7a77db5 100644
--- a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java
+++ b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/EmailQueryViewPopulator.java
@@ -189,8 +189,7 @@ public class EmailQueryViewPopulator {
     }
 
     private Mono<MessageManager> retrieveMailbox(MailboxSession session, MailboxMetaData mailboxMetadata) {
-        return Mono.fromCallable(() -> mailboxManager.getMailbox(mailboxMetadata.getId(), session))
-            .subscribeOn(Schedulers.elastic());
+        return Mono.from(mailboxManager.getMailboxReactive(mailboxMetadata.getId(), session));
     }
 
     private Flux<MessageResult> listAllMessages(MessageManager messageManager, MailboxSession session) {
diff --git a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
index da0a6d7..054f85d 100644
--- a/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
+++ b/server/protocols/webadmin/webadmin-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
@@ -211,8 +211,7 @@ public class MessageFastViewProjectionCorrector {
     }
 
     private Mono<MessageManager> retrieveMailbox(MailboxSession session, MailboxMetaData mailboxMetadata) {
-        return Mono.fromCallable(() -> mailboxManager.getMailbox(mailboxMetadata.getId(), session))
-            .subscribeOn(Schedulers.elastic());
+        return Mono.from(mailboxManager.getMailboxReactive(mailboxMetadata.getId(), session));
     }
 
     private Flux<ComposedMessageIdWithMetaData> listAllMailboxMessages(MessageManager messageManager, MailboxSession session) {

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