You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ro...@apache.org on 2019/05/02 12:42:59 UTC

[james-project] 01/06: JMAP getMailboxes preload quotas for user namespace/name in order to avoid doing it for each mailbox

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

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

commit 7bf9d99ac8524bac5fe0b587732f4ab08394d396
Author: RĂ©mi Kowalski <rk...@linagora.com>
AuthorDate: Tue Apr 23 17:19:35 2019 +0200

    JMAP getMailboxes preload quotas for user namespace/name in order to avoid doing it for each mailbox
---
 .../james/jmap/methods/GetMailboxesMethod.java     | 38 ++++++++++++++------
 .../apache/james/jmap/model/MailboxFactory.java    | 42 +++++++++++++++++-----
 .../apache/james/jmap/model/mailbox/Quotas.java    | 15 ++++++++
 .../james/jmap/model/mailbox/QuotaIdTest.java      | 32 +++++++++++++++++
 4 files changed, 108 insertions(+), 19 deletions(-)

diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMailboxesMethod.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMailboxesMethod.java
index 9b33064..ab22edc 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMailboxesMethod.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/GetMailboxesMethod.java
@@ -33,6 +33,7 @@ import org.apache.james.jmap.model.GetMailboxesResponse;
 import org.apache.james.jmap.model.MailboxFactory;
 import org.apache.james.jmap.model.MailboxProperty;
 import org.apache.james.jmap.model.mailbox.Mailbox;
+import org.apache.james.jmap.model.mailbox.Quotas;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.exception.MailboxException;
@@ -44,6 +45,7 @@ import org.apache.james.util.MDCBuilder;
 import org.apache.james.util.OptionalUtils;
 
 import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -54,6 +56,8 @@ public class GetMailboxesMethod implements Method {
 
     private static final Method.Request.Name METHOD_NAME = Method.Request.name("getMailboxes");
     private static final Method.Response.Name RESPONSE_NAME = Method.Response.name("mailboxes");
+    private static final Optional<List<MailboxMetaData>> NO_PRELOADED_METADATA = Optional.empty();
+    private static final Optional<Quotas> NO_PRELOADED_QUOTAS = Optional.empty();
 
     private final MailboxManager mailboxManager; 
     private final MailboxFactory mailboxFactory;
@@ -106,10 +110,10 @@ public class GetMailboxesMethod implements Method {
         GetMailboxesResponse.Builder builder = GetMailboxesResponse.builder();
         try {
             Optional<ImmutableList<MailboxId>> mailboxIds = mailboxesRequest.getIds();
-            retrieveMailboxes(mailboxIds, mailboxSession)
+            List<Mailbox> mailboxes = retrieveMailboxes(mailboxIds, mailboxSession)
                 .sorted(Comparator.comparing(Mailbox::getSortOrder))
-                .forEach(builder::add);
-            return builder.build();
+                .collect(Guavate.toImmutableList());
+            return builder.addAll(mailboxes).build();
         } catch (MailboxException e) {
             throw new RuntimeException(e);
         }
@@ -121,31 +125,43 @@ public class GetMailboxesMethod implements Method {
             .orElseGet(Throwing.supplier(() -> retrieveAllMailboxes(mailboxSession)).sneakyThrow());
     }
 
+
+
     private Stream<Mailbox> retrieveSpecificMailboxes(MailboxSession mailboxSession, ImmutableList<MailboxId> mailboxIds) {
         return mailboxIds
             .stream()
-            .map(mailboxId -> mailboxFactory.builder()
+            .map(mailboxId ->  mailboxFactory.builder()
                 .id(mailboxId)
                 .session(mailboxSession)
-                .build())
+                .usingPreloadedMailboxesMetadata(NO_PRELOADED_METADATA)
+                .usingPreloadedUserDefaultQuotas(NO_PRELOADED_QUOTAS)
+                .build()
+            )
             .flatMap(OptionalUtils::toStream);
     }
 
     private Stream<Mailbox> retrieveAllMailboxes(MailboxSession mailboxSession) throws MailboxException {
-        List<MailboxMetaData> userMailboxes = mailboxManager.search(
-            MailboxQuery.builder()
-                .matchesAllMailboxNames()
-                .build(),
-            mailboxSession);
+        List<MailboxMetaData> userMailboxes = getAllMailboxesMetaData(mailboxSession);
+        Quotas mailboxQuotas =  mailboxFactory.getUserDefaultQuotas(mailboxSession);
+
         return userMailboxes
             .stream()
             .map(MailboxMetaData::getId)
             .map(mailboxId -> mailboxFactory.builder()
                 .id(mailboxId)
                 .session(mailboxSession)
-                .usingPreloadedMailboxesMetadata(userMailboxes)
+                .usingPreloadedMailboxesMetadata(Optional.of(userMailboxes))
+                .usingPreloadedUserDefaultQuotas(Optional.of(mailboxQuotas))
                 .build())
             .flatMap(OptionalUtils::toStream);
     }
 
+    private List<MailboxMetaData> getAllMailboxesMetaData(MailboxSession mailboxSession) throws MailboxException {
+        return mailboxManager.search(
+                MailboxQuery.builder()
+                    .matchesAllMailboxNames()
+                    .build(),
+                mailboxSession);
+    }
+
 }
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MailboxFactory.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MailboxFactory.java
index 0080339..d2506fb 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MailboxFactory.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MailboxFactory.java
@@ -59,7 +59,8 @@ public class MailboxFactory {
         private final MailboxFactory mailboxFactory;
         private MailboxSession session;
         private MailboxId id;
-        private List<MailboxMetaData> userMailboxesMetadata;
+        private Optional<List<MailboxMetaData>> userMailboxesMetadata = Optional.empty();
+        private Optional<Quotas> preloadedUserDefaultQuotas = Optional.empty();
 
         private MailboxBuilder(MailboxFactory mailboxFactory) {
             this.mailboxFactory = mailboxFactory;
@@ -75,18 +76,23 @@ public class MailboxFactory {
             return this;
         }
 
-        public MailboxBuilder usingPreloadedMailboxesMetadata(List<MailboxMetaData> userMailboxesMetadata) {
+        public MailboxBuilder usingPreloadedMailboxesMetadata(Optional<List<MailboxMetaData>> userMailboxesMetadata) {
             this.userMailboxesMetadata = userMailboxesMetadata;
             return this;
         }
 
+        public MailboxBuilder usingPreloadedUserDefaultQuotas(Optional<Quotas> preloadedUserDefaultQuotas) {
+            this.preloadedUserDefaultQuotas = preloadedUserDefaultQuotas;
+            return this;
+        }
+
         public Optional<Mailbox> build() {
             Preconditions.checkNotNull(id);
             Preconditions.checkNotNull(session);
 
             try {
                 MessageManager mailbox = mailboxFactory.mailboxManager.getMailbox(id, session);
-                return Optional.of(mailboxFactory.fromMessageManager(mailbox, Optional.ofNullable(userMailboxesMetadata), session));
+                return Optional.of(mailboxFactory.fromMessageManager(mailbox, userMailboxesMetadata, preloadedUserDefaultQuotas, session));
             } catch (MailboxNotFoundException e) {
                 return Optional.empty();
             } catch (MailboxException e) {
@@ -106,8 +112,10 @@ public class MailboxFactory {
         return new MailboxBuilder(this);
     }
 
-    private Mailbox fromMessageManager(MessageManager messageManager, Optional<List<MailboxMetaData>> userMailboxesMetadata,
-                                                 MailboxSession mailboxSession) throws MailboxException {
+    private Mailbox fromMessageManager(MessageManager messageManager,
+                                       Optional<List<MailboxMetaData>> userMailboxesMetadata,
+                                       Optional<Quotas> preloadedDefaultUserQuotas,
+                                       MailboxSession mailboxSession) throws MailboxException {
         MailboxPath mailboxPath = messageManager.getMailboxPath();
         boolean isOwner = mailboxPath.belongsTo(mailboxSession);
         Optional<Role> role = Role.from(mailboxPath.getName());
@@ -116,7 +124,8 @@ public class MailboxFactory {
         Rights rights = Rights.fromACL(messageManager.getResolvedAcl(mailboxSession))
             .removeEntriesFor(Username.forMailboxPath(mailboxPath));
         Username username = Username.fromSession(mailboxSession);
-        Quotas quotas = getQuotas(mailboxPath);
+
+        Quotas quotas = getQuotas(mailboxPath, preloadedDefaultUserQuotas);
 
         return Mailbox.builder()
             .id(messageManager.getId())
@@ -138,15 +147,32 @@ public class MailboxFactory {
             .build();
     }
 
-    private Quotas getQuotas(MailboxPath mailboxPath) throws MailboxException {
+    private Quotas getQuotas(MailboxPath mailboxPath, Optional<Quotas> preloadedUserDefaultQuotas) throws MailboxException {
         QuotaRoot quotaRoot = quotaRootResolver.getQuotaRoot(mailboxPath);
+        QuotaId quotaId = QuotaId.fromQuotaRoot(quotaRoot);
+
+        if (containsQuotaId(preloadedUserDefaultQuotas, quotaId)) {
+            return preloadedUserDefaultQuotas.get();
+        }
         return Quotas.from(
-            QuotaId.fromQuotaRoot(quotaRoot),
+            quotaId,
             Quotas.Quota.from(
                 quotaToValue(quotaManager.getStorageQuota(quotaRoot)),
                 quotaToValue(quotaManager.getMessageQuota(quotaRoot))));
     }
 
+    private boolean containsQuotaId(Optional<Quotas> preloadedUserDefaultQuotas, QuotaId quotaId) {
+        return preloadedUserDefaultQuotas
+                .map(Quotas::getQuotas)
+                .map(quotaIdQuotaMap -> quotaIdQuotaMap.containsKey(quotaId))
+                .orElse(false);
+    }
+
+    public Quotas getUserDefaultQuotas(MailboxSession mailboxSession) throws MailboxException {
+        MailboxPath inboxPath = MailboxPath.inbox(mailboxSession);
+        return getQuotas(inboxPath, Optional.empty());
+    }
+
     private <T extends QuotaValue<T>> Quotas.Value<T> quotaToValue(Quota<T> quota) {
         return new Quotas.Value<>(
                 quotaValueToNumber(quota.getUsed()),
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Quotas.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Quotas.java
index 30ae9a2..a090cb5 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Quotas.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/mailbox/Quotas.java
@@ -19,6 +19,7 @@
 package org.apache.james.jmap.model.mailbox;
 
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 
 import org.apache.james.core.quota.QuotaCount;
@@ -66,6 +67,20 @@ public class Quotas {
         public String getName() {
             return quotaRoot.getValue();
         }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof QuotaId) {
+                QuotaId other = (QuotaId) o;
+                return Objects.equals(quotaRoot, other.quotaRoot);
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hashCode(quotaRoot);
+        }
     }
 
     public static class Quota {
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/QuotaIdTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/QuotaIdTest.java
new file mode 100644
index 0000000..591b69d
--- /dev/null
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/mailbox/QuotaIdTest.java
@@ -0,0 +1,32 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.james.jmap.model.mailbox;
+
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class QuotaIdTest {
+
+    @Test
+    public void shouldRespectJavaBeanContract() {
+        EqualsVerifier.forClass(Quotas.QuotaId.class).verify();
+    }
+
+}


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