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 2023/05/17 01:40:32 UTC

[james-project] 04/07: [PERF] Disable JMAP related listeners if JMAP is disabled

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 414bacdcc443bcacd59f779e4a6be47b4db344c9
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue May 2 10:17:36 2023 +0700

    [PERF] Disable JMAP related listeners if JMAP is disabled
    
     -> There are procedures to populate JMAP projections if need be
     -> JMAP listeners are expensive performance wise and there is no reason IMAP only
     users pays that price
---
 .../james/CassandraJamesServerConfiguration.java   | 27 +++++++++++++--
 .../org/apache/james/CassandraJamesServerMain.java | 13 +++++++-
 .../james/CassandraRabbitMQJamesConfiguration.java | 25 ++++++++++++--
 .../james/CassandraRabbitMQJamesServerMain.java    | 13 +++++++-
 .../org/apache/james/MemoryJamesConfiguration.java | 27 +++++++++++++--
 .../org/apache/james/MemoryJamesServerMain.java    | 13 +++++++-
 .../apache/james/jmap/draft/JMAPCommonModule.java  |  6 +---
 .../james/jmap/draft/JMAPListenerModule.java       | 38 ++++++++++++++++++++++
 .../org/apache/james/jmap/draft/JMAPModule.java    | 34 +++++++++----------
 9 files changed, 164 insertions(+), 32 deletions(-)

diff --git a/server/apps/cassandra-app/src/main/java/org/apache/james/CassandraJamesServerConfiguration.java b/server/apps/cassandra-app/src/main/java/org/apache/james/CassandraJamesServerConfiguration.java
index cad9040715..7d93448da5 100644
--- a/server/apps/cassandra-app/src/main/java/org/apache/james/CassandraJamesServerConfiguration.java
+++ b/server/apps/cassandra-app/src/main/java/org/apache/james/CassandraJamesServerConfiguration.java
@@ -20,12 +20,14 @@
 package org.apache.james;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.util.Optional;
 
 import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.james.data.UsersRepositoryModuleChooser;
 import org.apache.james.filesystem.api.FileSystem;
 import org.apache.james.filesystem.api.JamesDirectoriesProvider;
+import org.apache.james.jmap.draft.JMAPModule;
 import org.apache.james.server.core.JamesServerResourceLoader;
 import org.apache.james.server.core.MissingArgumentException;
 import org.apache.james.server.core.configuration.Configuration;
@@ -52,6 +54,7 @@ public class CassandraJamesServerConfiguration implements Configuration {
         private Optional<BlobStoreConfiguration> blobStoreConfiguration;
         private Optional<UsersRepositoryModuleChooser.Implementation> usersRepositoryImplementation;
         private Optional<VaultConfiguration> vaultConfiguration;
+        private Optional<Boolean> jmapEnabled;
 
         private Builder() {
             rootDirectory = Optional.empty();
@@ -60,6 +63,7 @@ public class CassandraJamesServerConfiguration implements Configuration {
             usersRepositoryImplementation = Optional.empty();
             blobStoreConfiguration = Optional.empty();
             vaultConfiguration = Optional.empty();
+            jmapEnabled = Optional.empty();
         }
 
         public Builder workingDirectory(String path) {
@@ -138,7 +142,17 @@ public class CassandraJamesServerConfiguration implements Configuration {
                 }
             });
 
-            return new CassandraJamesServerConfiguration(configurationPath, directories, searchConfiguration, blobStoreConfiguration, usersRepositoryChoice, vaultConfiguration);
+            boolean jmapEnabled = this.jmapEnabled.orElseGet(() -> {
+                try {
+                    return JMAPModule.parseConfiguration(propertiesProvider).isEnabled();
+                } catch (FileNotFoundException e) {
+                    return false;
+                } catch (ConfigurationException e) {
+                    throw new RuntimeException(e);
+                }
+            });
+
+            return new CassandraJamesServerConfiguration(configurationPath, directories, searchConfiguration, blobStoreConfiguration, usersRepositoryChoice, vaultConfiguration, jmapEnabled);
         }
     }
 
@@ -152,14 +166,19 @@ public class CassandraJamesServerConfiguration implements Configuration {
     private final BlobStoreConfiguration blobStoreConfiguration;
     private final UsersRepositoryModuleChooser.Implementation usersRepositoryImplementation;
     private final VaultConfiguration vaultConfiguration;
+    private final boolean jmapEnabled;
 
-    private CassandraJamesServerConfiguration(ConfigurationPath configurationPath, JamesDirectoriesProvider directories, SearchConfiguration searchConfiguration, BlobStoreConfiguration blobStoreConfiguration, UsersRepositoryModuleChooser.Implementation usersRepositoryImplementation, VaultConfiguration vaultConfiguration) {
+    private CassandraJamesServerConfiguration(ConfigurationPath configurationPath, JamesDirectoriesProvider directories,
+                                              SearchConfiguration searchConfiguration, BlobStoreConfiguration blobStoreConfiguration,
+                                              UsersRepositoryModuleChooser.Implementation usersRepositoryImplementation,
+                                              VaultConfiguration vaultConfiguration, boolean jmapEnabled) {
         this.configurationPath = configurationPath;
         this.directories = directories;
         this.searchConfiguration = searchConfiguration;
         this.blobStoreConfiguration = blobStoreConfiguration;
         this.usersRepositoryImplementation = usersRepositoryImplementation;
         this.vaultConfiguration = vaultConfiguration;
+        this.jmapEnabled = jmapEnabled;
     }
 
     @Override
@@ -187,4 +206,8 @@ public class CassandraJamesServerConfiguration implements Configuration {
     public BlobStoreConfiguration getBlobStoreConfiguration() {
         return blobStoreConfiguration;
     }
+
+    public boolean isJmapEnabled() {
+        return jmapEnabled;
+    }
 }
diff --git a/server/apps/cassandra-app/src/main/java/org/apache/james/CassandraJamesServerMain.java b/server/apps/cassandra-app/src/main/java/org/apache/james/CassandraJamesServerMain.java
index 47906848d1..c0cf0d93ab 100644
--- a/server/apps/cassandra-app/src/main/java/org/apache/james/CassandraJamesServerMain.java
+++ b/server/apps/cassandra-app/src/main/java/org/apache/james/CassandraJamesServerMain.java
@@ -23,6 +23,7 @@ import java.util.Set;
 
 import org.apache.james.data.UsersRepositoryModuleChooser;
 import org.apache.james.eventsourcing.eventstore.cassandra.EventNestedTypes;
+import org.apache.james.jmap.draft.JMAPListenerModule;
 import org.apache.james.json.DTOModule;
 import org.apache.james.modules.BlobExportMechanismModule;
 import org.apache.james.modules.CassandraConsistencyTaskSerializationModule;
@@ -194,7 +195,8 @@ public class CassandraJamesServerMain implements JamesServerMain {
             .combineWith(SearchModuleChooser.chooseModules(configuration.searchConfiguration()))
             .combineWith(new UsersRepositoryModuleChooser(new CassandraUsersRepositoryModule())
                 .chooseModules(configuration.getUsersRepositoryImplementation()))
-            .combineWith(chooseDeletedMessageVault(configuration.getVaultConfiguration()));
+            .combineWith(chooseDeletedMessageVault(configuration.getVaultConfiguration()))
+            .combineWith(chooseJmapModule(configuration));
     }
 
     private static Module chooseDeletedMessageVault(VaultConfiguration vaultConfiguration) {
@@ -207,4 +209,13 @@ public class CassandraJamesServerMain implements JamesServerMain {
 
         };
     }
+
+    private static Module chooseJmapModule(CassandraJamesServerConfiguration configuration) {
+        if (configuration.isJmapEnabled()) {
+            return new JMAPListenerModule();
+        }
+        return binder -> {
+
+        };
+    }
 }
diff --git a/server/apps/distributed-app/src/main/java/org/apache/james/CassandraRabbitMQJamesConfiguration.java b/server/apps/distributed-app/src/main/java/org/apache/james/CassandraRabbitMQJamesConfiguration.java
index 3c5ccac9f4..2be534aaaf 100644
--- a/server/apps/distributed-app/src/main/java/org/apache/james/CassandraRabbitMQJamesConfiguration.java
+++ b/server/apps/distributed-app/src/main/java/org/apache/james/CassandraRabbitMQJamesConfiguration.java
@@ -20,12 +20,14 @@
 package org.apache.james;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.util.Optional;
 
 import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.james.data.UsersRepositoryModuleChooser;
 import org.apache.james.filesystem.api.FileSystem;
 import org.apache.james.filesystem.api.JamesDirectoriesProvider;
+import org.apache.james.jmap.draft.JMAPModule;
 import org.apache.james.modules.blobstore.BlobStoreConfiguration;
 import org.apache.james.modules.queue.rabbitmq.MailQueueViewChoice;
 import org.apache.james.server.core.JamesServerResourceLoader;
@@ -47,6 +49,7 @@ public class CassandraRabbitMQJamesConfiguration implements Configuration {
         private Optional<MailQueueViewChoice> mailQueueViewChoice;
         private Optional<UsersRepositoryModuleChooser.Implementation> usersRepositoryImplementation;
         private Optional<VaultConfiguration> vaultConfiguration;
+        private Optional<Boolean> jmapEnabled;
 
         private Builder() {
             searchConfiguration = Optional.empty();
@@ -56,6 +59,7 @@ public class CassandraRabbitMQJamesConfiguration implements Configuration {
             usersRepositoryImplementation = Optional.empty();
             mailQueueViewChoice = Optional.empty();
             vaultConfiguration = Optional.empty();
+            jmapEnabled = Optional.empty();
         }
 
         public Builder workingDirectory(String path) {
@@ -142,13 +146,24 @@ public class CassandraRabbitMQJamesConfiguration implements Configuration {
                 }
             });
 
+            boolean jmapEnabled = this.jmapEnabled.orElseGet(() -> {
+                try {
+                    return JMAPModule.parseConfiguration(propertiesProvider).isEnabled();
+                } catch (FileNotFoundException e) {
+                    return false;
+                } catch (ConfigurationException e) {
+                    throw new RuntimeException(e);
+                }
+            });
+
             return new CassandraRabbitMQJamesConfiguration(
                 configurationPath,
                 directories,
                 blobStoreConfiguration,
                 searchConfiguration,
                 usersRepositoryChoice,
-                mailQueueViewChoice, vaultConfiguration);
+                mailQueueViewChoice, vaultConfiguration,
+                jmapEnabled);
         }
     }
 
@@ -163,8 +178,9 @@ public class CassandraRabbitMQJamesConfiguration implements Configuration {
     private final UsersRepositoryModuleChooser.Implementation usersRepositoryImplementation;
     private final MailQueueViewChoice mailQueueViewChoice;
     private final VaultConfiguration vaultConfiguration;
+    private final boolean jmapEnabled;
 
-    public CassandraRabbitMQJamesConfiguration(ConfigurationPath configurationPath, JamesDirectoriesProvider directories, BlobStoreConfiguration blobStoreConfiguration, SearchConfiguration searchConfiguration, UsersRepositoryModuleChooser.Implementation usersRepositoryImplementation, MailQueueViewChoice mailQueueViewChoice, VaultConfiguration vaultConfiguration) {
+    public CassandraRabbitMQJamesConfiguration(ConfigurationPath configurationPath, JamesDirectoriesProvider directories, BlobStoreConfiguration blobStoreConfiguration, SearchConfiguration searchConfiguration, UsersRepositoryModuleChooser.Implementation usersRepositoryImplementation, MailQueueViewChoice mailQueueViewChoice, VaultConfiguration vaultConfiguration, boolean jmapEnabled) {
         this.configurationPath = configurationPath;
         this.directories = directories;
         this.blobStoreConfiguration = blobStoreConfiguration;
@@ -172,6 +188,7 @@ public class CassandraRabbitMQJamesConfiguration implements Configuration {
         this.usersRepositoryImplementation = usersRepositoryImplementation;
         this.mailQueueViewChoice = mailQueueViewChoice;
         this.vaultConfiguration = vaultConfiguration;
+        this.jmapEnabled = jmapEnabled;
     }
 
     public MailQueueViewChoice getMailQueueViewChoice() {
@@ -203,4 +220,8 @@ public class CassandraRabbitMQJamesConfiguration implements Configuration {
     public VaultConfiguration getVaultConfiguration() {
         return vaultConfiguration;
     }
+
+    public boolean isJmapEnabled() {
+        return jmapEnabled;
+    }
 }
diff --git a/server/apps/distributed-app/src/main/java/org/apache/james/CassandraRabbitMQJamesServerMain.java b/server/apps/distributed-app/src/main/java/org/apache/james/CassandraRabbitMQJamesServerMain.java
index 703a75986c..e94f99be7d 100644
--- a/server/apps/distributed-app/src/main/java/org/apache/james/CassandraRabbitMQJamesServerMain.java
+++ b/server/apps/distributed-app/src/main/java/org/apache/james/CassandraRabbitMQJamesServerMain.java
@@ -23,6 +23,7 @@ import java.util.Set;
 
 import org.apache.james.data.UsersRepositoryModuleChooser;
 import org.apache.james.eventsourcing.eventstore.cassandra.EventNestedTypes;
+import org.apache.james.jmap.draft.JMAPListenerModule;
 import org.apache.james.json.DTO;
 import org.apache.james.json.DTOModule;
 import org.apache.james.modules.BlobExportMechanismModule;
@@ -200,7 +201,8 @@ public class CassandraRabbitMQJamesServerMain implements JamesServerMain {
             .combineWith(SearchModuleChooser.chooseModules(searchConfiguration))
             .combineWith(new UsersRepositoryModuleChooser(new CassandraUsersRepositoryModule())
                 .chooseModules(configuration.getUsersRepositoryImplementation()))
-            .combineWith(chooseDeletedMessageVault(configuration.getVaultConfiguration()));
+            .combineWith(chooseDeletedMessageVault(configuration.getVaultConfiguration()))
+            .combineWith(chooseJmapModule(configuration));
     }
 
     private static Module chooseDeletedMessageVault(VaultConfiguration vaultConfiguration) {
@@ -213,4 +215,13 @@ public class CassandraRabbitMQJamesServerMain implements JamesServerMain {
 
         };
     }
+
+    private static Module chooseJmapModule(CassandraRabbitMQJamesConfiguration configuration) {
+        if (configuration.isJmapEnabled()) {
+            return new JMAPListenerModule();
+        }
+        return binder -> {
+
+        };
+    }
 }
diff --git a/server/apps/memory-app/src/main/java/org/apache/james/MemoryJamesConfiguration.java b/server/apps/memory-app/src/main/java/org/apache/james/MemoryJamesConfiguration.java
index b8b34298ec..530df09e2b 100644
--- a/server/apps/memory-app/src/main/java/org/apache/james/MemoryJamesConfiguration.java
+++ b/server/apps/memory-app/src/main/java/org/apache/james/MemoryJamesConfiguration.java
@@ -20,27 +20,33 @@
 package org.apache.james;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.util.Optional;
 
+import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.james.data.UsersRepositoryModuleChooser;
 import org.apache.james.filesystem.api.FileSystem;
 import org.apache.james.filesystem.api.JamesDirectoriesProvider;
+import org.apache.james.jmap.draft.JMAPModule;
 import org.apache.james.server.core.JamesServerResourceLoader;
 import org.apache.james.server.core.MissingArgumentException;
 import org.apache.james.server.core.configuration.Configuration;
 import org.apache.james.server.core.configuration.FileConfigurationProvider;
 import org.apache.james.server.core.filesystem.FileSystemImpl;
+import org.apache.james.utils.PropertiesProvider;
 
 public class MemoryJamesConfiguration implements Configuration {
     public static class Builder {
         private Optional<String> rootDirectory;
         private Optional<ConfigurationPath> configurationPath;
         private Optional<UsersRepositoryModuleChooser.Implementation> usersRepositoryImplementation;
+        private Optional<Boolean> jmapEnabled;
 
         private Builder() {
             rootDirectory = Optional.empty();
             configurationPath = Optional.empty();
             usersRepositoryImplementation = Optional.empty();
+            jmapEnabled = Optional.empty();
         }
 
         public Builder workingDirectory(String path) {
@@ -90,10 +96,21 @@ public class MemoryJamesConfiguration implements Configuration {
             UsersRepositoryModuleChooser.Implementation usersRepositoryChoice = usersRepositoryImplementation.orElseGet(
                 () -> UsersRepositoryModuleChooser.Implementation.parse(configurationProvider));
 
+            boolean jmapEnabled = this.jmapEnabled.orElseGet(() -> {
+                PropertiesProvider propertiesProvider = new PropertiesProvider(fileSystem, configurationPath);
+                try {
+                    return JMAPModule.parseConfiguration(propertiesProvider).isEnabled();
+                } catch (FileNotFoundException e) {
+                    return false;
+                } catch (ConfigurationException e) {
+                    throw new RuntimeException(e);
+                }
+            });
+
             return new MemoryJamesConfiguration(
                 configurationPath,
                 directories,
-                usersRepositoryChoice);
+                usersRepositoryChoice, jmapEnabled);
         }
     }
 
@@ -104,11 +121,13 @@ public class MemoryJamesConfiguration implements Configuration {
     private final ConfigurationPath configurationPath;
     private final JamesDirectoriesProvider directories;
     private final UsersRepositoryModuleChooser.Implementation usersRepositoryImplementation;
+    private final boolean jmapEnabled;
 
-    public MemoryJamesConfiguration(ConfigurationPath configurationPath, JamesDirectoriesProvider directories, UsersRepositoryModuleChooser.Implementation usersRepositoryImplementation) {
+    public MemoryJamesConfiguration(ConfigurationPath configurationPath, JamesDirectoriesProvider directories, UsersRepositoryModuleChooser.Implementation usersRepositoryImplementation, boolean jmapEnabled) {
         this.configurationPath = configurationPath;
         this.directories = directories;
         this.usersRepositoryImplementation = usersRepositoryImplementation;
+        this.jmapEnabled = jmapEnabled;
     }
 
     @Override
@@ -124,4 +143,8 @@ public class MemoryJamesConfiguration implements Configuration {
     public UsersRepositoryModuleChooser.Implementation getUsersRepositoryImplementation() {
         return usersRepositoryImplementation;
     }
+
+    public boolean isJmapEnabled() {
+        return jmapEnabled;
+    }
 }
diff --git a/server/apps/memory-app/src/main/java/org/apache/james/MemoryJamesServerMain.java b/server/apps/memory-app/src/main/java/org/apache/james/MemoryJamesServerMain.java
index b206505a58..c3a4ef8498 100644
--- a/server/apps/memory-app/src/main/java/org/apache/james/MemoryJamesServerMain.java
+++ b/server/apps/memory-app/src/main/java/org/apache/james/MemoryJamesServerMain.java
@@ -22,6 +22,7 @@ package org.apache.james;
 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
 import org.apache.james.data.UsersRepositoryModuleChooser;
 import org.apache.james.jmap.api.identity.CustomIdentityDAO;
+import org.apache.james.jmap.draft.JMAPListenerModule;
 import org.apache.james.jmap.memory.identity.MemoryCustomIdentityDAO;
 import org.apache.james.jmap.memory.pushsubscription.MemoryPushSubscriptionModule;
 import org.apache.james.jwt.JwtConfiguration;
@@ -168,7 +169,17 @@ public class MemoryJamesServerMain implements JamesServerMain {
         return GuiceJamesServer.forConfiguration(configuration)
             .combineWith(IN_MEMORY_SERVER_AGGREGATE_MODULE)
             .combineWith(new UsersRepositoryModuleChooser(new MemoryUsersRepositoryModule())
-                .chooseModules(configuration.getUsersRepositoryImplementation()));
+                .chooseModules(configuration.getUsersRepositoryImplementation()))
+            .combineWith(chooseJmapModule(configuration));
+    }
+
+    private static Module chooseJmapModule(MemoryJamesConfiguration configuration) {
+        if (configuration.isJmapEnabled()) {
+            return new JMAPListenerModule();
+        }
+        return binder -> {
+
+        };
     }
 
 }
diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPCommonModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPCommonModule.java
index e43c402e34..db07f8f3e8 100644
--- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPCommonModule.java
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPCommonModule.java
@@ -20,7 +20,6 @@ package org.apache.james.jmap.draft;
 
 import java.util.concurrent.TimeUnit;
 
-import org.apache.james.events.EventListener;
 import org.apache.james.jmap.api.access.AccessTokenRepository;
 import org.apache.james.jmap.draft.api.AccessTokenManager;
 import org.apache.james.jmap.draft.api.SimpleTokenFactory;
@@ -37,7 +36,6 @@ import org.apache.james.jmap.draft.model.message.view.MessageFullViewFactory;
 import org.apache.james.jmap.draft.model.message.view.MessageHeaderViewFactory;
 import org.apache.james.jmap.draft.model.message.view.MessageMetadataViewFactory;
 import org.apache.james.jmap.draft.send.MailSpool;
-import org.apache.james.jmap.event.ComputeMessageFastViewProjectionListener;
 import org.apache.james.lifecycle.api.ConfigurationSanitizer;
 import org.apache.james.lifecycle.api.StartUpCheck;
 import org.apache.james.util.date.DefaultZonedDateTimeProvider;
@@ -81,9 +79,7 @@ public class JMAPCommonModule extends AbstractModule {
         bindConstant().annotatedWith(Names.named(AccessTokenRepository.TOKEN_EXPIRATION_IN_MS)).to(DEFAULT_TOKEN_EXPIRATION_IN_MS);
         bind(AccessTokenManager.class).to(AccessTokenManagerImpl.class);
 
-        Multibinder.newSetBinder(binder(), EventListener.ReactiveGroupEventListener.class)
-            .addBinding()
-            .to(ComputeMessageFastViewProjectionListener.class);
+
 
         Multibinder.newSetBinder(binder(), StartUpCheck.class)
             .addBinding().to(JMAPConfigurationStartUpCheck.class);
diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPListenerModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPListenerModule.java
new file mode 100644
index 0000000000..7be302bfae
--- /dev/null
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPListenerModule.java
@@ -0,0 +1,38 @@
+/****************************************************************
+ * 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.draft;
+
+import org.apache.james.events.EventListener;
+import org.apache.james.jmap.change.MailboxChangeListener;
+import org.apache.james.jmap.event.ComputeMessageFastViewProjectionListener;
+import org.apache.james.jmap.event.PropagateLookupRightListener;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+
+public class JMAPListenerModule extends AbstractModule {
+    @Override
+    protected void configure() {
+        Multibinder.newSetBinder(binder(), EventListener.GroupEventListener.class).addBinding().to(PropagateLookupRightListener.class);
+        Multibinder.newSetBinder(binder(), EventListener.ReactiveGroupEventListener.class).addBinding().to(MailboxChangeListener.class);
+        Multibinder.newSetBinder(binder(), EventListener.ReactiveGroupEventListener.class)
+            .addBinding()
+            .to(ComputeMessageFastViewProjectionListener.class);
+    }
+}
diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPModule.java
index 0844923902..2f43328ffe 100644
--- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPModule.java
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPModule.java
@@ -31,12 +31,10 @@ import javax.inject.Named;
 import org.apache.commons.configuration2.Configuration;
 import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.commons.io.FileUtils;
-import org.apache.james.events.EventListener;
 import org.apache.james.filesystem.api.FileSystem;
 import org.apache.james.jmap.JMAPConfiguration;
 import org.apache.james.jmap.JMAPServer;
 import org.apache.james.jmap.Version;
-import org.apache.james.jmap.change.MailboxChangeListener;
 import org.apache.james.jmap.core.CapabilityFactory;
 import org.apache.james.jmap.core.CoreCapabilityFactory;
 import org.apache.james.jmap.core.DelegationCapabilityFactory$;
@@ -53,7 +51,6 @@ import org.apache.james.jmap.core.WebSocketCapabilityFactory$;
 import org.apache.james.jmap.draft.methods.RequestHandler;
 import org.apache.james.jmap.draft.send.PostDequeueDecoratorFactory;
 import org.apache.james.jmap.draft.utils.JsoupHtmlTextExtractor;
-import org.apache.james.jmap.event.PropagateLookupRightListener;
 import org.apache.james.jmap.mailet.filter.JMAPFiltering;
 import org.apache.james.jmap.rfc8621.RFC8621MethodsModule;
 import org.apache.james.jwt.JwtConfiguration;
@@ -137,9 +134,6 @@ public class JMAPModule extends AbstractModule {
 
         bind(MailQueueItemDecoratorFactory.class).to(PostDequeueDecoratorFactory.class).in(Scopes.SINGLETON);
 
-        Multibinder.newSetBinder(binder(), EventListener.GroupEventListener.class).addBinding().to(PropagateLookupRightListener.class);
-        Multibinder.newSetBinder(binder(), EventListener.ReactiveGroupEventListener.class).addBinding().to(MailboxChangeListener.class);
-
         Multibinder<Version> supportedVersions = Multibinder.newSetBinder(binder(), Version.class);
         supportedVersions.addBinding().toInstance(Version.DRAFT);
         supportedVersions.addBinding().toInstance(Version.RFC8621);
@@ -190,18 +184,7 @@ public class JMAPModule extends AbstractModule {
     @Singleton
     JMAPConfiguration provideConfiguration(PropertiesProvider propertiesProvider) throws ConfigurationException {
         try {
-            Configuration configuration = propertiesProvider.getConfiguration("jmap");
-            return JMAPConfiguration.builder()
-                .enabled(configuration.getBoolean("enabled", true))
-                .port(Port.of(configuration.getInt("jmap.port", DEFAULT_JMAP_PORT)))
-                .enableEmailQueryView(Optional.ofNullable(configuration.getBoolean("view.email.query.enabled", null)))
-                .userProvisioningEnabled(Optional.ofNullable(configuration.getBoolean("user.provisioning.enabled", null)))
-                .defaultVersion(Optional.ofNullable(configuration.getString("jmap.version.default", null))
-                    .map(Version::of))
-                .maximumSendSize(Optional.ofNullable(configuration.getString("email.send.max.size", null))
-                    .map(Throwing.function(Size::parse))
-                    .map(Size::asBytes))
-                .build();
+            return parseConfiguration(propertiesProvider);
         } catch (FileNotFoundException e) {
             LOGGER.warn("Could not find JMAP configuration file. JMAP server will not be enabled.");
             return JMAPConfiguration.builder()
@@ -210,6 +193,21 @@ public class JMAPModule extends AbstractModule {
         }
     }
 
+    public static JMAPConfiguration parseConfiguration(PropertiesProvider propertiesProvider) throws FileNotFoundException, ConfigurationException {
+        Configuration configuration = propertiesProvider.getConfiguration("jmap");
+        return JMAPConfiguration.builder()
+            .enabled(configuration.getBoolean("enabled", true))
+            .port(Port.of(configuration.getInt("jmap.port", DEFAULT_JMAP_PORT)))
+            .enableEmailQueryView(Optional.ofNullable(configuration.getBoolean("view.email.query.enabled", null)))
+            .userProvisioningEnabled(Optional.ofNullable(configuration.getBoolean("user.provisioning.enabled", null)))
+            .defaultVersion(Optional.ofNullable(configuration.getString("jmap.version.default", null))
+                .map(Version::of))
+            .maximumSendSize(Optional.ofNullable(configuration.getString("email.send.max.size", null))
+                .map(Throwing.function(Size::parse))
+                .map(Size::asBytes))
+            .build();
+    }
+
     @Provides
     @Singleton
     JMAPDraftConfiguration provideDraftConfiguration(PropertiesProvider propertiesProvider, FileSystem fileSystem) throws ConfigurationException, IOException {


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