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 <[email protected]> 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: [email protected] For additional commands, e-mail: [email protected]
