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:35 UTC

[james-project] 03/15: [REFACTORING] Fasten JMAP Mailbox/get Reactive quotas

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 7c4bda28c236bebe51f0aa4b5e8b3bf87fb555bd
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri May 7 18:13:13 2021 +0700

    [REFACTORING] Fasten JMAP Mailbox/get Reactive quotas
---
 .../james/mailbox/quota/MaxQuotaManager.java       | 22 ++++++++
 .../apache/james/mailbox/quota/QuotaManager.java   |  3 ++
 .../james/mailbox/quota/QuotaRootResolver.java     |  4 ++
 .../quota/CassandraPerUserMaxQuotaManager.java     | 44 +++++++++-------
 .../store/quota/DefaultUserQuotaRootResolver.java  | 15 +++++-
 .../store/quota/ListeningCurrentQuotaUpdater.java  |  4 +-
 .../james/mailbox/store/quota/NoQuotaManager.java  |  8 +++
 .../mailbox/store/quota/StoreQuotaManager.java     | 27 ++++++++--
 .../draft/utils/quotas/DefaultQuotaLoader.java     | 25 +++++----
 .../james/jmap/draft/utils/quotas/QuotaLoader.java |  5 +-
 .../quotas/QuotaLoaderWithDefaultPreloaded.java    | 61 +++++++++-------------
 .../james/jmap/utils/quotas/QuotaLoader.scala      |  2 -
 .../quotas/QuotaLoaderWithPreloadedDefault.scala   | 13 ++---
 .../james/jmap/utils/quotas/QuotaReader.scala      | 16 +++---
 14 files changed, 155 insertions(+), 94 deletions(-)

diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/quota/MaxQuotaManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/quota/MaxQuotaManager.java
index b105b42..3d2cb5c 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/quota/MaxQuotaManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/quota/MaxQuotaManager.java
@@ -32,9 +32,13 @@ import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.Quota;
 import org.apache.james.mailbox.model.Quota.Scope;
 import org.apache.james.mailbox.model.QuotaRoot;
+import org.reactivestreams.Publisher;
 
 import com.github.fge.lambdas.Throwing;
 
+import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
+
 /**
  * This interface describe how to set the max quotas for users
  * Part of RFC 2087 implementation
@@ -150,12 +154,30 @@ public interface MaxQuotaManager {
 
     Map<Quota.Scope, QuotaCountLimit> listMaxMessagesDetails(QuotaRoot quotaRoot);
 
+    default Publisher<Map<Scope, QuotaCountLimit>> listMaxMessagesDetailsReactive(QuotaRoot quotaRoot) {
+        return Mono.fromCallable(() -> listMaxMessagesDetails(quotaRoot))
+            .subscribeOn(Schedulers.elastic());
+    }
+
     Map<Quota.Scope, QuotaSizeLimit> listMaxStorageDetails(QuotaRoot quotaRoot);
 
+    default Publisher<Map<Quota.Scope, QuotaSizeLimit>> listMaxStorageDetailsReactive(QuotaRoot quotaRoot) {
+        return Mono.fromCallable(() -> listMaxStorageDetails(quotaRoot))
+            .subscribeOn(Schedulers.elastic());
+    }
+
+
     default QuotaDetails quotaDetails(QuotaRoot quotaRoot) {
         return new QuotaDetails(listMaxMessagesDetails(quotaRoot), listMaxStorageDetails(quotaRoot));
     }
 
+    default Publisher<QuotaDetails> quotaDetailsReactive(QuotaRoot quotaRoot) {
+        return Mono.zip(
+            Mono.from(listMaxMessagesDetailsReactive(quotaRoot)),
+            Mono.from(listMaxStorageDetailsReactive(quotaRoot)))
+            .map(tuple -> new QuotaDetails(tuple.getT1(), tuple.getT2()));
+    }
+
     Optional<QuotaCountLimit> getDomainMaxMessage(Domain domain);
 
     void setDomainMaxMessage(Domain domain, QuotaCountLimit count) throws MailboxException;
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/quota/QuotaManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/quota/QuotaManager.java
index a08c0bc..4d34ecf 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/quota/QuotaManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/quota/QuotaManager.java
@@ -25,6 +25,7 @@ import org.apache.james.core.quota.QuotaSizeUsage;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.Quota;
 import org.apache.james.mailbox.model.QuotaRoot;
+import org.reactivestreams.Publisher;
 
 
 /**
@@ -68,4 +69,6 @@ public interface QuotaManager {
     Quota<QuotaSizeLimit, QuotaSizeUsage> getStorageQuota(QuotaRoot quotaRoot) throws MailboxException;
 
     Quotas getQuotas(QuotaRoot quotaRoot) throws MailboxException;
+
+    Publisher<Quotas> getQuotasReactive(QuotaRoot quotaRoot);
 }
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/quota/QuotaRootResolver.java b/mailbox/api/src/main/java/org/apache/james/mailbox/quota/QuotaRootResolver.java
index 60510f6..efbc244 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/quota/QuotaRootResolver.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/quota/QuotaRootResolver.java
@@ -37,10 +37,14 @@ public interface QuotaRootResolver extends QuotaRootDeserializer {
      */
     QuotaRoot getQuotaRoot(MailboxPath mailboxPath) throws MailboxException;
 
+    Publisher<QuotaRoot> getQuotaRootReactive(MailboxPath mailboxPath);
+
     QuotaRoot getQuotaRoot(MailboxId mailboxId) throws MailboxException;
 
     QuotaRoot getQuotaRoot(Mailbox mailbox) throws MailboxException;
 
+    Publisher<QuotaRoot> getQuotaRootReactive(Mailbox mailbox);
+
     Publisher<QuotaRoot> getQuotaRootReactive(MailboxId mailboxId);
 
     Publisher<Mailbox> retrieveAssociatedMailboxes(QuotaRoot quotaRoot, MailboxSession mailboxSession);
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManager.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManager.java
index 5fe0095..dd6884b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManager.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserMaxQuotaManager.java
@@ -136,34 +136,42 @@ public class CassandraPerUserMaxQuotaManager implements MaxQuotaManager {
 
     @Override
     public Map<Quota.Scope, QuotaCountLimit> listMaxMessagesDetails(QuotaRoot quotaRoot) {
+        return listMaxMessagesDetailsReactive(quotaRoot).block();
+    }
+
+    @Override
+    public Mono<Map<Quota.Scope, QuotaCountLimit>> listMaxMessagesDetailsReactive(QuotaRoot quotaRoot) {
         return Flux.merge(
-                perUserQuota.getMaxMessage(quotaRoot)
-                    .map(limit -> Pair.of(Quota.Scope.User, limit)),
-                Mono.justOrEmpty(quotaRoot.getDomain())
-                    .flatMap(perDomainQuota::getMaxMessage)
-                    .map(limit -> Pair.of(Quota.Scope.Domain, limit)),
-                globalQuota.getGlobalMaxMessage()
-                    .map(limit -> Pair.of(Quota.Scope.Global, limit)))
+            perUserQuota.getMaxMessage(quotaRoot)
+                .map(limit -> Pair.of(Quota.Scope.User, limit)),
+            Mono.justOrEmpty(quotaRoot.getDomain())
+                .flatMap(perDomainQuota::getMaxMessage)
+                .map(limit -> Pair.of(Quota.Scope.Domain, limit)),
+            globalQuota.getGlobalMaxMessage()
+                .map(limit -> Pair.of(Quota.Scope.Global, limit)))
             .collect(Guavate.toImmutableMap(
                 Pair::getKey,
-                Pair::getValue))
-            .block();
+                Pair::getValue));
     }
 
     @Override
     public Map<Quota.Scope, QuotaSizeLimit> listMaxStorageDetails(QuotaRoot quotaRoot) {
+        return listMaxStorageDetailsReactive(quotaRoot).block();
+    }
+
+    @Override
+    public Mono<Map<Quota.Scope, QuotaSizeLimit>> listMaxStorageDetailsReactive(QuotaRoot quotaRoot) {
         return Flux.merge(
-                perUserQuota.getMaxStorage(quotaRoot)
-                    .map(limit -> Pair.of(Quota.Scope.User, limit)),
-                Mono.justOrEmpty(quotaRoot.getDomain())
-                    .flatMap(perDomainQuota::getMaxStorage)
-                    .map(limit -> Pair.of(Quota.Scope.Domain, limit)),
-                globalQuota.getGlobalMaxStorage()
-                    .map(limit -> Pair.of(Quota.Scope.Global, limit)))
+            perUserQuota.getMaxStorage(quotaRoot)
+                .map(limit -> Pair.of(Quota.Scope.User, limit)),
+            Mono.justOrEmpty(quotaRoot.getDomain())
+                .flatMap(perDomainQuota::getMaxStorage)
+                .map(limit -> Pair.of(Quota.Scope.Domain, limit)),
+            globalQuota.getGlobalMaxStorage()
+                .map(limit -> Pair.of(Quota.Scope.Global, limit)))
             .collect(Guavate.toImmutableMap(
                 Pair::getKey,
-                Pair::getValue))
-            .block();
+                Pair::getValue));
     }
 
     @Override
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/DefaultUserQuotaRootResolver.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/DefaultUserQuotaRootResolver.java
index b6f2069..629d6aa 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/DefaultUserQuotaRootResolver.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/DefaultUserQuotaRootResolver.java
@@ -37,6 +37,7 @@ import org.apache.james.mailbox.model.search.MailboxQuery;
 import org.apache.james.mailbox.quota.QuotaRootDeserializer;
 import org.apache.james.mailbox.quota.UserQuotaRootResolver;
 import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
+import org.reactivestreams.Publisher;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
@@ -95,12 +96,12 @@ public class DefaultUserQuotaRootResolver implements UserQuotaRootResolver {
     }
 
     @Override
-    public QuotaRoot getQuotaRoot(Mailbox mailbox) throws MailboxException {
+    public QuotaRoot getQuotaRoot(Mailbox mailbox) {
         return getQuotaRoot(mailbox.generateAssociatedPath());
     }
 
     @Override
-    public QuotaRoot getQuotaRoot(MailboxId mailboxId) throws MailboxException {
+    public QuotaRoot getQuotaRoot(MailboxId mailboxId) {
         return getQuotaRootReactive(mailboxId).block();
     }
 
@@ -116,6 +117,16 @@ public class DefaultUserQuotaRootResolver implements UserQuotaRootResolver {
     }
 
     @Override
+    public Publisher<QuotaRoot> getQuotaRootReactive(MailboxPath mailboxPath) {
+        return Mono.just(getQuotaRoot(mailboxPath));
+    }
+
+    @Override
+    public Publisher<QuotaRoot> getQuotaRootReactive(Mailbox mailbox) {
+        return Mono.just(getQuotaRoot(mailbox));
+    }
+
+    @Override
     public QuotaRoot fromString(String serializedQuotaRoot) throws MailboxException {
         return QUOTA_ROOT_DESERIALIZER.fromString(serializedQuotaRoot);
     }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/ListeningCurrentQuotaUpdater.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/ListeningCurrentQuotaUpdater.java
index 2bafe64..cfe2d80 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/ListeningCurrentQuotaUpdater.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/ListeningCurrentQuotaUpdater.java
@@ -110,9 +110,7 @@ public class ListeningCurrentQuotaUpdater implements EventListener.ReactiveGroup
     }
 
     private Mono<Void> dispatchNewQuota(QuotaRoot quotaRoot, Username username) {
-        Mono<QuotaManager.Quotas> quotasMono = Mono.fromCallable(() -> quotaManager.getQuotas(quotaRoot));
-
-        return quotasMono.subscribeOn(Schedulers.elastic())
+        return Mono.from(quotaManager.getQuotasReactive(quotaRoot))
             .flatMap(quotas -> eventBus.dispatch(
                 EventFactory.quotaUpdated()
                     .randomEventId()
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/NoQuotaManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/NoQuotaManager.java
index e40b084..89e3d63 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/NoQuotaManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/NoQuotaManager.java
@@ -26,6 +26,9 @@ import org.apache.james.core.quota.QuotaSizeUsage;
 import org.apache.james.mailbox.model.Quota;
 import org.apache.james.mailbox.model.QuotaRoot;
 import org.apache.james.mailbox.quota.QuotaManager;
+import org.reactivestreams.Publisher;
+
+import reactor.core.publisher.Mono;
 
 /**
  * This quota manager is intended to be used when you want to deactivate the Quota feature
@@ -52,4 +55,9 @@ public class NoQuotaManager implements QuotaManager {
     public Quotas getQuotas(QuotaRoot quotaRoot) {
         return new Quotas(getMessageQuota(quotaRoot), getStorageQuota(quotaRoot));
     }
+
+    @Override
+    public Publisher<Quotas> getQuotasReactive(QuotaRoot quotaRoot) {
+        return Mono.just(getQuotas(quotaRoot));
+    }
 }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/StoreQuotaManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/StoreQuotaManager.java
index 17d80e7..aa010bc 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/StoreQuotaManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/quota/StoreQuotaManager.java
@@ -27,7 +27,6 @@ import org.apache.james.core.quota.QuotaCountLimit;
 import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeLimit;
 import org.apache.james.core.quota.QuotaSizeUsage;
-import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.CurrentQuotas;
 import org.apache.james.mailbox.model.Quota;
 import org.apache.james.mailbox.model.Quota.Scope;
@@ -35,8 +34,10 @@ import org.apache.james.mailbox.model.QuotaRoot;
 import org.apache.james.mailbox.quota.CurrentQuotaManager;
 import org.apache.james.mailbox.quota.MaxQuotaManager;
 import org.apache.james.mailbox.quota.QuotaManager;
+import org.reactivestreams.Publisher;
 
 import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
 
 /**
  * Default implementation for the Quota Manager.
@@ -54,7 +55,7 @@ public class StoreQuotaManager implements QuotaManager {
     }
 
     @Override
-    public Quota<QuotaCountLimit, QuotaCountUsage> getMessageQuota(QuotaRoot quotaRoot) throws MailboxException {
+    public Quota<QuotaCountLimit, QuotaCountUsage> getMessageQuota(QuotaRoot quotaRoot) {
         Map<Scope, QuotaCountLimit> maxMessageDetails = maxQuotaManager.listMaxMessagesDetails(quotaRoot);
         return Quota.<QuotaCountLimit, QuotaCountUsage>builder()
             .used(Mono.from(currentQuotaManager.getCurrentMessageCount(quotaRoot)).block())
@@ -65,7 +66,7 @@ public class StoreQuotaManager implements QuotaManager {
 
 
     @Override
-    public Quota<QuotaSizeLimit, QuotaSizeUsage> getStorageQuota(QuotaRoot quotaRoot) throws MailboxException {
+    public Quota<QuotaSizeLimit, QuotaSizeUsage> getStorageQuota(QuotaRoot quotaRoot) {
         Map<Scope, QuotaSizeLimit> maxStorageDetails = maxQuotaManager.listMaxStorageDetails(quotaRoot);
         return Quota.<QuotaSizeLimit, QuotaSizeUsage>builder()
             .used(Mono.from(currentQuotaManager.getCurrentStorage(quotaRoot)).block())
@@ -75,7 +76,7 @@ public class StoreQuotaManager implements QuotaManager {
     }
 
     @Override
-    public Quotas getQuotas(QuotaRoot quotaRoot) throws MailboxException {
+    public Quotas getQuotas(QuotaRoot quotaRoot) {
         MaxQuotaManager.QuotaDetails quotaDetails = maxQuotaManager.quotaDetails(quotaRoot);
         CurrentQuotas currentQuotas = Mono.from(currentQuotaManager.getCurrentQuotas(quotaRoot)).block();
         return new Quotas(
@@ -90,4 +91,22 @@ public class StoreQuotaManager implements QuotaManager {
                 .limitsByScope(quotaDetails.getMaxStorageDetails())
                 .build());
     }
+
+    @Override
+    public Publisher<Quotas> getQuotasReactive(QuotaRoot quotaRoot) {
+        return Mono.zip(
+                Mono.from(maxQuotaManager.quotaDetailsReactive(quotaRoot)),
+                Mono.from(currentQuotaManager.getCurrentQuotas(quotaRoot)))
+            .map(tuple -> new Quotas(
+                Quota.<QuotaCountLimit, QuotaCountUsage>builder()
+                    .used(tuple.getT2().count())
+                    .computedLimit(maxQuotaManager.getMaxMessage(tuple.getT1().getMaxMessageDetails()).orElse(QuotaCountLimit.unlimited()))
+                    .limitsByScope(tuple.getT1().getMaxMessageDetails())
+                    .build(),
+                Quota.<QuotaSizeLimit, QuotaSizeUsage>builder()
+                    .used(tuple.getT2().size())
+                    .computedLimit(maxQuotaManager.getMaxStorage(tuple.getT1().getMaxStorageDetails()).orElse(QuotaSizeLimit.unlimited()))
+                    .limitsByScope(tuple.getT1().getMaxStorageDetails())
+                    .build()));
+    }
 }
\ No newline at end of file
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/DefaultQuotaLoader.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/DefaultQuotaLoader.java
index 25a851f..e1aa415 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/DefaultQuotaLoader.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/DefaultQuotaLoader.java
@@ -21,12 +21,12 @@ package org.apache.james.jmap.draft.utils.quotas;
 import javax.inject.Inject;
 
 import org.apache.james.jmap.draft.model.mailbox.Quotas;
-import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.QuotaRoot;
 import org.apache.james.mailbox.quota.QuotaManager;
 import org.apache.james.mailbox.quota.QuotaRootResolver;
 
+import reactor.core.publisher.Mono;
+
 public class DefaultQuotaLoader extends QuotaLoader {
 
     private final QuotaRootResolver quotaRootResolver;
@@ -38,15 +38,18 @@ public class DefaultQuotaLoader extends QuotaLoader {
         this.quotaManager = quotaManager;
     }
 
-    public Quotas getQuotas(MailboxPath mailboxPath) throws MailboxException {
-        QuotaRoot quotaRoot = quotaRootResolver.getQuotaRoot(mailboxPath);
-        Quotas.QuotaId quotaId = Quotas.QuotaId.fromQuotaRoot(quotaRoot);
-        QuotaManager.Quotas quotas = quotaManager.getQuotas(quotaRoot);
-        return Quotas.from(
-            quotaId,
-            Quotas.Quota.from(
-                quotaToValue(quotas.getStorageQuota()),
-                quotaToValue(quotas.getMessageQuota())));
+    public Mono<Quotas> getQuotas(MailboxPath mailboxPath) {
+        return Mono.from(quotaRootResolver.getQuotaRootReactive(mailboxPath))
+            .flatMap(quotaRoot -> Mono.from(quotaManager.getQuotasReactive(quotaRoot))
+                .map(quotas -> {
+                    Quotas.QuotaId quotaId = Quotas.QuotaId.fromQuotaRoot(quotaRoot);
+
+                    return Quotas.from(
+                        quotaId,
+                        Quotas.Quota.from(
+                            quotaToValue(quotas.getStorageQuota()),
+                            quotaToValue(quotas.getMessageQuota())));
+                }));
     }
 
 }
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/QuotaLoader.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/QuotaLoader.java
index 76bd371..77a6aea 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/QuotaLoader.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/QuotaLoader.java
@@ -24,13 +24,14 @@ import org.apache.james.core.quota.QuotaLimitValue;
 import org.apache.james.core.quota.QuotaUsageValue;
 import org.apache.james.jmap.draft.model.Number;
 import org.apache.james.jmap.draft.model.mailbox.Quotas;
-import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.Quota;
 
+import reactor.core.publisher.Mono;
+
 public abstract class QuotaLoader {
 
-    public abstract Quotas getQuotas(MailboxPath mailboxPath) throws MailboxException;
+    public abstract Mono<Quotas> getQuotas(MailboxPath mailboxPath);
 
     protected <T extends QuotaLimitValue<T>, U extends QuotaUsageValue<U, T>> Quotas.Value<T, U> quotaToValue(Quota<T, U> quota) {
         return new Quotas.Value<>(
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/QuotaLoaderWithDefaultPreloaded.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/QuotaLoaderWithDefaultPreloaded.java
index 326f0d2..876dfbd 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/QuotaLoaderWithDefaultPreloaded.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/utils/quotas/QuotaLoaderWithDefaultPreloaded.java
@@ -22,42 +22,44 @@ import java.util.Optional;
 
 import org.apache.james.jmap.draft.model.mailbox.Quotas;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.QuotaRoot;
 import org.apache.james.mailbox.quota.QuotaManager;
 import org.apache.james.mailbox.quota.QuotaRootResolver;
 
+import reactor.core.publisher.Mono;
+
 public class QuotaLoaderWithDefaultPreloaded extends QuotaLoader {
 
+    public static Mono<QuotaLoaderWithDefaultPreloaded> preLoad(QuotaRootResolver quotaRootResolver,
+                                            QuotaManager quotaManager,
+                                            MailboxSession session) {
+        DefaultQuotaLoader defaultQuotaLoader = new DefaultQuotaLoader(quotaRootResolver, quotaManager);
+
+        return defaultQuotaLoader.getQuotas(MailboxPath.inbox(session))
+            .map(Optional::of)
+            .switchIfEmpty(Mono.just(Optional.empty()))
+            .map(quotas -> new QuotaLoaderWithDefaultPreloaded(quotaRootResolver, defaultQuotaLoader, quotas));
+    }
+
     private final QuotaRootResolver quotaRootResolver;
-    private final QuotaManager quotaManager;
+    private final DefaultQuotaLoader defaultQuotaLoader;
     private final Optional<Quotas> preloadedUserDefaultQuotas;
-    private final MailboxSession session;
 
-    public QuotaLoaderWithDefaultPreloaded(QuotaRootResolver quotaRootResolver,
-                                           QuotaManager quotaManager,
-                                           MailboxSession session) throws MailboxException {
+    private QuotaLoaderWithDefaultPreloaded(QuotaRootResolver quotaRootResolver, DefaultQuotaLoader defaultQuotaLoader, Optional<Quotas> preloadedUserDefaultQuotas) {
         this.quotaRootResolver = quotaRootResolver;
-        this.quotaManager = quotaManager;
-        this.session = session;
-        preloadedUserDefaultQuotas = Optional.of(getUserDefaultQuotas());
-
+        this.defaultQuotaLoader = defaultQuotaLoader;
+        this.preloadedUserDefaultQuotas = preloadedUserDefaultQuotas;
     }
 
-    public Quotas getQuotas(MailboxPath mailboxPath) throws MailboxException {
-        QuotaRoot quotaRoot = quotaRootResolver.getQuotaRoot(mailboxPath);
-        Quotas.QuotaId quotaId = Quotas.QuotaId.fromQuotaRoot(quotaRoot);
-
-        if (containsQuotaId(preloadedUserDefaultQuotas, quotaId)) {
-            return preloadedUserDefaultQuotas.get();
-        }
-        QuotaManager.Quotas quotas = quotaManager.getQuotas(quotaRoot);
-        return Quotas.from(
-            quotaId,
-            Quotas.Quota.from(
-                quotaToValue(quotas.getStorageQuota()),
-                quotaToValue(quotas.getMessageQuota())));
+    public Mono<Quotas> getQuotas(MailboxPath mailboxPath) {
+        return Mono.from(quotaRootResolver.getQuotaRootReactive(mailboxPath))
+            .flatMap(quotaRoot -> {
+                Quotas.QuotaId quotaId = Quotas.QuotaId.fromQuotaRoot(quotaRoot);
+                if (containsQuotaId(preloadedUserDefaultQuotas, quotaId)) {
+                    return Mono.just(preloadedUserDefaultQuotas.get());
+                }
+                return defaultQuotaLoader.getQuotas(mailboxPath);
+            });
     }
 
     private boolean containsQuotaId(Optional<Quotas> preloadedUserDefaultQuotas, Quotas.QuotaId quotaId) {
@@ -67,15 +69,4 @@ public class QuotaLoaderWithDefaultPreloaded extends QuotaLoader {
             .orElse(false);
     }
 
-    private Quotas getUserDefaultQuotas() throws MailboxException {
-        QuotaRoot quotaRoot = quotaRootResolver.getQuotaRoot(MailboxPath.inbox(session));
-        Quotas.QuotaId quotaId = Quotas.QuotaId.fromQuotaRoot(quotaRoot);
-        QuotaManager.Quotas quotas = quotaManager.getQuotas(quotaRoot);
-        return Quotas.from(
-            quotaId,
-            Quotas.Quota.from(
-                quotaToValue(quotas.getStorageQuota()),
-                quotaToValue(quotas.getMessageQuota())));
-    }
-
 }
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaLoader.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaLoader.scala
index 0c770c7..447ca25 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaLoader.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaLoader.scala
@@ -20,11 +20,9 @@
 package org.apache.james.jmap.utils.quotas
 
 import org.apache.james.jmap.mail.Quotas
-import org.apache.james.mailbox.exception.MailboxException
 import org.apache.james.mailbox.model.MailboxPath
 import reactor.core.scala.publisher.SMono
 
 trait QuotaLoader {
-  @throws[MailboxException]
   def getQuotas(mailboxPath: MailboxPath): SMono[Quotas]
 }
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaLoaderWithPreloadedDefault.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaLoaderWithPreloadedDefault.scala
index 8a4c458..6e56928 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaLoaderWithPreloadedDefault.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaLoaderWithPreloadedDefault.scala
@@ -22,7 +22,6 @@ package org.apache.james.jmap.utils.quotas
 import javax.inject.Inject
 import org.apache.james.jmap.mail.{QuotaRoot, Quotas}
 import org.apache.james.mailbox.MailboxSession
-import org.apache.james.mailbox.exception.MailboxException
 import org.apache.james.mailbox.model.{MailboxPath, QuotaRoot => ModelQuotaRoot}
 import org.apache.james.mailbox.quota.UserQuotaRootResolver
 import reactor.core.scala.publisher.SMono
@@ -31,14 +30,13 @@ import reactor.core.scala.publisher.SMono
 class QuotaLoaderWithPreloadedDefaultFactory @Inject()(quotaRootResolver: UserQuotaRootResolver, quotaReader: QuotaReader) {
 
   def loadFor(session: MailboxSession): SMono[QuotaLoaderWithPreloadedDefault] =
-    SMono.fromCallable(() => new QuotaLoaderWithPreloadedDefault(
+    getUserDefaultQuotas(session)
+      .map(qotas => new QuotaLoaderWithPreloadedDefault(
         quotaRootResolver,
         quotaReader,
         session,
-        getUserDefaultQuotas(session)))
+        qotas))
 
-
-  @throws[MailboxException]
   private def getUserDefaultQuotas(session:MailboxSession): SMono[Quotas] = {
     val quotaRoot: ModelQuotaRoot = quotaRootResolver.forUser(session.getUser)
     quotaReader.retrieveQuotas(QuotaRoot.toJmap(quotaRoot))
@@ -48,11 +46,10 @@ class QuotaLoaderWithPreloadedDefaultFactory @Inject()(quotaRootResolver: UserQu
 class QuotaLoaderWithPreloadedDefault(quotaRootResolver: UserQuotaRootResolver,
                                       quotaReader: QuotaReader,
                                       session: MailboxSession,
-                                      preloadedUserDefaultQuotas: SMono[Quotas]) extends QuotaLoader {
-  @throws[MailboxException]
+                                      preloadedUserDefaultQuotas: Quotas) extends QuotaLoader {
   override def getQuotas(mailboxPath: MailboxPath): SMono[Quotas] =
     if (mailboxPath.belongsTo(session)) {
-      preloadedUserDefaultQuotas
+      SMono.just(preloadedUserDefaultQuotas)
     } else {
       val quotaRoot: ModelQuotaRoot = quotaRootResolver.getQuotaRoot(mailboxPath)
       quotaReader.retrieveQuotas(QuotaRoot.toJmap(quotaRoot))
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaReader.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaReader.scala
index de77245..de646c0 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaReader.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/utils/quotas/QuotaReader.scala
@@ -31,15 +31,13 @@ import reactor.core.scala.publisher.SMono
 
 class QuotaReader @Inject() (quotaManager: QuotaManager) {
   @throws[MailboxException]
-  def retrieveQuotas(quotaRoot: QuotaRoot): SMono[Quotas] = {
-    val quotaId = QuotaId.fromQuotaRoot(quotaRoot)
-    val quotas = quotaManager.getQuotas(quotaRoot.toModel)
-    SMono.just(Quotas.from(
-      quotaId,
-      Quota.from(Map(
-        Quotas.Storage -> quotaToValue(quotas.getStorageQuota),
-        Quotas.Message -> quotaToValue(quotas.getMessageQuota)))))
-  }
+  def retrieveQuotas(quotaRoot: QuotaRoot): SMono[Quotas] =
+    SMono(quotaManager.getQuotasReactive(quotaRoot.toModel))
+      .map(quotas => Quotas.from(
+        QuotaId.fromQuotaRoot(quotaRoot),
+        Quota.from(Map(
+          Quotas.Storage -> quotaToValue(quotas.getStorageQuota),
+          Quotas.Message -> quotaToValue(quotas.getMessageQuota)))))
 
   private def quotaToValue[T <: QuotaLimitValue[T], U <: QuotaUsageValue[U, T]](quota: ModelQuota[T, U]): Value =
     Value(

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