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 f6670e96f631ef64a526aacf2cf72ab351d8f01c
Author: Benoit Tellier <btell...@linagora.com>
AuthorDate: Thu Nov 7 14:46:45 2019 +0700

    JAMES-2632 Optimize get all mailboxes
---
 .../jmap/draft/methods/GetMailboxesMethod.java     |  5 +-
 .../james/jmap/draft/model/MailboxFactory.java     | 76 ++++++++++++++++++----
 .../james/jmap/draft/model/MailboxFactoryTest.java | 58 ++++++++++++++++-
 3 files changed, 122 insertions(+), 17 deletions(-)

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 b53565f..64623d1 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
@@ -151,9 +151,8 @@ public class GetMailboxesMethod implements Method {
 
         return userMailboxes
             .stream()
-            .map(MailboxMetaData::getId)
-            .map(mailboxId -> mailboxFactory.builder()
-                .id(mailboxId)
+            .map(mailboxMetaData -> mailboxFactory.builder()
+                .mailboxMetadata(mailboxMetaData)
                 .session(mailboxSession)
                 .usingPreloadedMailboxesMetadata(Optional.of(userMailboxes))
                 .quotaLoader(quotaLoader)
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 a8f097d..796cf59 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
@@ -37,16 +37,22 @@ 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;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxMetaData;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.quota.QuotaManager;
 import org.apache.james.mailbox.quota.QuotaRootResolver;
+import org.apache.james.util.OptionalUtils;
 
+import com.github.fge.lambdas.Throwing;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
+import com.google.common.primitives.Booleans;
+
+import reactor.core.publisher.Mono;
 
 public class MailboxFactory {
     private final MailboxManager mailboxManager;
@@ -57,7 +63,8 @@ public class MailboxFactory {
         private final MailboxFactory mailboxFactory;
         private QuotaLoader quotaLoader;
         private MailboxSession session;
-        private MailboxId id;
+        private Optional<MailboxId> id = Optional.empty();
+        private Optional<MailboxMetaData> mailboxMetaData = Optional.empty();
         private Optional<List<MailboxMetaData>> userMailboxesMetadata = 
Optional.empty();
 
         private MailboxBuilder(MailboxFactory mailboxFactory, QuotaLoader 
quotaLoader) {
@@ -66,7 +73,12 @@ public class MailboxFactory {
         }
 
         public MailboxBuilder id(MailboxId id) {
-            this.id = id;
+            this.id = Optional.of(id);
+            return this;
+        }
+
+        public MailboxBuilder mailboxMetadata(MailboxMetaData mailboxMetaData) 
{
+            this.mailboxMetaData = Optional.of(mailboxMetaData);
             return this;
         }
 
@@ -86,18 +98,55 @@ public class MailboxFactory {
         }
 
         public Optional<Mailbox> build() {
-            Preconditions.checkNotNull(id);
             Preconditions.checkNotNull(session);
 
             try {
-                MessageManager mailbox = 
mailboxFactory.mailboxManager.getMailbox(id, session);
-                return Optional.of(mailboxFactory.fromMessageManager(mailbox, 
userMailboxesMetadata, quotaLoader, session));
+                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 mailboxCounters = 
mailboxMetaData.map(MailboxMetaData::getCounters)
+                    .orElseGet(Throwing.supplier(() -> 
retrieveCachedMailbox(mailboxId, 
mailbox).getMailboxCounters(session)).sneakyThrow());
+
+                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);
             }
         }
+
+        private MailboxId computeMailboxId() {
+            int idCount = Booleans.countTrue(id.isPresent(), 
mailboxMetaData.isPresent());
+            Preconditions.checkState(idCount == 1, "You need exectly one 'id' 
'mailboxMetaData'");
+            return OptionalUtils.or(
+                id,
+                mailboxMetaData.map(MailboxMetaData::getId))
+                .get();
+        }
+
+        private Mono<MessageManager> mailbox(MailboxId mailboxId) {
+            return Mono.fromCallable(() -> 
mailboxFactory.mailboxManager.getMailbox(mailboxId, session));
+        }
+
+        private MessageManager retrieveCachedMailbox(MailboxId mailboxId, 
Mono<MessageManager> mailbox) throws MailboxNotFoundException {
+            return mailbox
+                .onErrorResume(MailboxNotFoundException.class, any -> 
Mono.empty())
+                .blockOptional()
+                .orElseThrow(() -> new MailboxNotFoundException(mailboxId));
+        }
     }
 
     @Inject
@@ -112,23 +161,24 @@ public class MailboxFactory {
         return new MailboxBuilder(this, defaultQuotaLoader);
     }
 
-    private Mailbox fromMessageManager(MessageManager messageManager,
-                                       Optional<List<MailboxMetaData>> 
userMailboxesMetadata,
-                                       QuotaLoader quotaLoader,
-                                       MailboxSession mailboxSession) throws 
MailboxException {
-        MailboxPath mailboxPath = messageManager.getMailboxPath();
+    private Mailbox from(MailboxId mailboxId,
+                         MailboxPath mailboxPath,
+                         MailboxCounters mailboxCounters,
+                         MailboxACL resolvedAcl,
+                         Optional<List<MailboxMetaData>> userMailboxesMetadata,
+                         QuotaLoader quotaLoader,
+                         MailboxSession mailboxSession) throws 
MailboxException {
         boolean isOwner = mailboxPath.belongsTo(mailboxSession);
         Optional<Role> role = Role.from(mailboxPath.getName());
-        MailboxCounters mailboxCounters = 
messageManager.getMailboxCounters(mailboxSession);
 
-        Rights rights = 
Rights.fromACL(messageManager.getResolvedAcl(mailboxSession))
+        Rights rights = Rights.fromACL(resolvedAcl)
             .removeEntriesFor(mailboxPath.getUser());
         Username username = mailboxSession.getUser();
 
         Quotas quotas = quotaLoader.getQuotas(mailboxPath);
 
         return Mailbox.builder()
-            .id(messageManager.getId())
+            .id(mailboxId)
             .name(getName(mailboxPath, mailboxSession))
             .parentId(getParentIdFromMailboxPath(mailboxPath, 
userMailboxesMetadata, mailboxSession).orElse(null))
             .role(role)
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 a082e7e..f9c437a 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
@@ -18,13 +18,17 @@
  ****************************************************************/
 package org.apache.james.jmap.draft.model;
 
+import static 
org.apache.james.mailbox.manager.ManagerTestProvisionner.OTHER_USER;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
 
 import java.util.Optional;
 
 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.Rights;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
@@ -34,6 +38,7 @@ import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxMetaData;
 import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.search.MailboxQuery;
 import org.apache.james.mailbox.quota.QuotaManager;
 import org.apache.james.mailbox.quota.QuotaRootResolver;
 import org.apache.james.mailbox.store.StoreMailboxManager;
@@ -43,6 +48,7 @@ import org.junit.Rule;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
 public class MailboxFactoryTest {
     public static final char DELIMITER = '.';
@@ -64,7 +70,7 @@ public class MailboxFactoryTest {
         QuotaManager quotaManager = 
mailboxManager.getQuotaComponents().getQuotaManager();
 
         user = ManagerTestProvisionner.USER;
-        otherUser = ManagerTestProvisionner.OTHER_USER;
+        otherUser = OTHER_USER;
         mailboxSession = mailboxManager.login(user, 
ManagerTestProvisionner.USER_PASS);
         otherMailboxSession = mailboxManager.login(otherUser, 
ManagerTestProvisionner.OTHER_USER_PASS);
         sut = new MailboxFactory(mailboxManager, quotaManager, 
quotaRootResolver);
@@ -306,4 +312,54 @@ public class MailboxFactoryTest {
         softly.assertThat(retrievedMailbox.isMayRemoveItems()).isTrue();
         softly.assertThat(retrievedMailbox.isMayRename()).isFalse();
     }
+
+    @Test
+    public void mailboxFromMetaDataShouldReturnPresentStoredValue() throws 
Exception {
+        String name = "myBox";
+        MailboxPath mailboxPath = MailboxPath.forUser(user, name);
+        mailboxManager.createMailbox(mailboxPath, mailboxSession);
+        mailboxManager.setRights(mailboxPath, 
MailboxACL.EMPTY.apply(MailboxACL.command()
+                .forUser(OTHER_USER)
+                .rights(MailboxACL.Right.Lookup, MailboxACL.Right.Read)
+                .asAddition()),
+            mailboxSession);
+        MailboxMetaData metaData = 
mailboxManager.search(MailboxQuery.privateMailboxesBuilder(mailboxSession).build(),
 mailboxSession)
+            .stream()
+            .filter(metadata -> metadata.getPath().equals(mailboxPath))
+            .findFirst()
+            .get();
+
+        Optional<Mailbox> mailbox = sut.builder()
+            .mailboxMetadata(metaData)
+            .session(mailboxSession)
+            .build();
+
+        softly.assertThat(mailbox).isPresent();
+        
softly.assertThat(mailbox).map(Mailbox::getId).contains(metaData.getId());
+        softly.assertThat(mailbox).map(Mailbox::getName).contains(name);
+        
softly.assertThat(mailbox).map(Mailbox::getTotalMessages).contains(Number.ZERO);
+        
softly.assertThat(mailbox).map(Mailbox::getUnreadMessages).contains(Number.ZERO);
+        softly.assertThat(mailbox).map(Mailbox::getSharedWith).contains(new 
Rights(ImmutableMap.of(
+            OTHER_USER, ImmutableList.of(Rights.Right.Lookup, 
Rights.Right.Read))));
+    }
+
+    @Test
+    public void buildShouldThrowWhenBothMetadataAndId() {
+        assertThatThrownBy(() ->
+            sut.builder()
+                .session(mailboxSession)
+                .id(mock(MailboxId.class))
+                .mailboxMetadata(mock(MailboxMetaData.class))
+                .build())
+            .isInstanceOf(IllegalStateException.class);
+    }
+
+    @Test
+    public void buildShouldThrowWhenNoId() {
+        assertThatThrownBy(() ->
+            sut.builder()
+                .session(mailboxSession)
+                .build())
+            .isInstanceOf(IllegalStateException.class);
+    }
 }


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

Reply via email to