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 bt...@apache.org on 2019/10/01 02:09:29 UTC

[james-project] branch master updated (94108cf -> e0cfb68)

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

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


    from 94108cf  JAMES-2902 Remove ProtocolHandlers default implementation for destroy/init
     new eacfeb4  JAMES-2886 MailRepositoryStore can also rely on GuiceGenericLoader
     new 066c6d9  JAMES-2563 Upgrade to ElasticSearch client 6.4.3
     new e0cfb68  JAMES-2563 Implement ElasticSearch healthCheck

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 backends-common/elasticsearch/pom.xml              |  6 +-
 .../backends/es/ElasticSearchHealthCheck.java      | 90 ++++++++++++++++++++++
 .../james/backends/es/ElasticSearchIndexer.java    |  6 +-
 .../james/backends/es/IndexCreationFactory.java    |  8 +-
 .../james/backends/es/NodeMappingFactory.java      |  6 +-
 .../es/ClientProviderImplConnectionTest.java       |  4 +-
 .../james/backends/es/DockerElasticSearch.java     | 18 ++++-
 .../james/backends/es/DockerElasticSearchRule.java |  2 +-
 .../es/ElasticSearchHealthCheckConnectionTest.java | 47 ++++++-----
 .../backends/es/ElasticSearchHealthCheckTest.java  | 79 +++++++++++++++++++
 .../backends/es/ElasticSearchIndexerTest.java      | 24 ++++--
 .../backends/es/search/ScrolledSearchTest.java     | 23 ++++--
 .../elasticsearch/ElasticSearchQuotaSearcher.java  |  3 +-
 pom.xml                                            |  6 ++
 .../data/CassandraMailRepositoryModule.java        |  5 --
 .../modules/mailbox/ElasticSearchClientModule.java | 23 ++++++
 .../modules/server/GuiceMailRepositoryLoader.java} | 40 +++++-----
 .../modules/server/MailStoreRepositoryModule.java  |  8 +-
 .../modules/data/JPAMailRepositoryModule.java      |  6 --
 .../james/modules/data/MemoryDataModule.java       |  5 --
 .../memory/MailRepositoryLoader.java}              | 14 +---
 .../memory/MemoryMailRepositoryStore.java          | 35 ++++-----
 .../memory/MemoryMailRepositoryStoreTest.java      | 24 +++---
 .../memory/TestingMailRepositoryLoader.java}       | 16 ++--
 server/mailet/mailets/pom.xml                      |  6 ++
 .../mailets/ToSenderDomainRepositoryTest.java      |  5 +-
 .../mailrepository/api/MailRepositoryProvider.java | 27 -------
 .../cassandra/CassandraMailRepository.java         | 16 +++-
 .../cassandra/CassandraMailRepositoryProvider.java | 53 -------------
 server/protocols/protocols-smtp/pom.xml            |  6 ++
 .../apache/james/smtpserver/SMTPServerTest.java    |  5 +-
 .../webadmin/webadmin-mailrepository/pom.xml       |  6 ++
 .../routes/MailRepositoriesRoutesTest.java         |  5 +-
 .../webadmin/service/ReprocessingServiceTest.java  |  5 +-
 34 files changed, 396 insertions(+), 236 deletions(-)
 create mode 100644 backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchHealthCheck.java
 copy mailbox/store/src/test/java/org/apache/james/mailbox/store/extractor/DefaultTextExtractorTest.java => backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchHealthCheckConnectionTest.java (55%)
 create mode 100644 backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchHealthCheckTest.java
 rename server/{data/data-file/src/main/java/org/apache/james/mailrepository/file/FileMailRepositoryProvider.java => container/guice/guice-common/src/main/java/org/apache/james/modules/server/GuiceMailRepositoryLoader.java} (50%)
 copy server/{mailrepository/mailrepository-memory/src/main/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryProvider.java => data/data-memory/src/main/java/org/apache/james/mailrepository/memory/MailRepositoryLoader.java} (77%)
 rename server/{mailrepository/mailrepository-memory/src/main/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryProvider.java => data/data-memory/src/test/java/org/apache/james/mailrepository/memory/TestingMailRepositoryLoader.java} (71%)
 delete mode 100644 server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryProvider.java
 delete mode 100644 server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryProvider.java


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


[james-project] 01/03: JAMES-2886 MailRepositoryStore can also rely on GuiceGenericLoader

Posted by bt...@apache.org.
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 eacfeb428f33be1a23aef8662b33158665184bba
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Sep 25 09:40:01 2019 +0700

    JAMES-2886 MailRepositoryStore can also rely on GuiceGenericLoader
---
 pom.xml                                            |  6 +++
 .../data/CassandraMailRepositoryModule.java        |  5 ---
 .../modules/server/GuiceMailRepositoryLoader.java} | 44 +++++++++++-----------
 .../modules/server/MailStoreRepositoryModule.java  |  8 ++--
 .../modules/data/JPAMailRepositoryModule.java      |  6 ---
 .../james/modules/data/MemoryDataModule.java       |  5 ---
 .../memory/MailRepositoryLoader.java}              | 14 ++-----
 .../memory/MemoryMailRepositoryStore.java          | 35 ++++++++---------
 .../memory/MemoryMailRepositoryStoreTest.java      | 24 ++++++------
 .../memory/TestingMailRepositoryLoader.java}       | 31 ++++-----------
 server/mailet/mailets/pom.xml                      |  6 +++
 .../mailets/ToSenderDomainRepositoryTest.java      |  5 +--
 .../mailrepository/api/MailRepositoryProvider.java | 27 -------------
 .../cassandra/CassandraMailRepository.java         | 16 ++++++--
 server/protocols/protocols-smtp/pom.xml            |  6 +++
 .../apache/james/smtpserver/SMTPServerTest.java    |  5 +--
 .../webadmin/webadmin-mailrepository/pom.xml       |  6 +++
 .../routes/MailRepositoriesRoutesTest.java         |  5 +--
 .../webadmin/service/ReprocessingServiceTest.java  |  5 +--
 19 files changed, 107 insertions(+), 152 deletions(-)

diff --git a/pom.xml b/pom.xml
index bae3b8e..5a60f56 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1356,6 +1356,12 @@
             </dependency>
             <dependency>
                 <groupId>${james.groupId}</groupId>
+                <artifactId>james-server-data-memory</artifactId>
+                <version>${project.version}</version>
+                <type>test-jar</type>
+            </dependency>
+            <dependency>
+                <groupId>${james.groupId}</groupId>
                 <artifactId>james-server-deleted-messages-vault</artifactId>
                 <version>${project.version}</version>
             </dependency>
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/data/CassandraMailRepositoryModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/data/CassandraMailRepositoryModule.java
index 3c8830b..b26dcf7 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/data/CassandraMailRepositoryModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/data/CassandraMailRepositoryModule.java
@@ -21,7 +21,6 @@ package org.apache.james.modules.data;
 
 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
 import org.apache.james.backends.cassandra.components.CassandraModule;
-import org.apache.james.mailrepository.api.MailRepositoryProvider;
 import org.apache.james.mailrepository.api.MailRepositoryUrlStore;
 import org.apache.james.mailrepository.api.Protocol;
 import org.apache.james.mailrepository.cassandra.CassandraMailRepository;
@@ -30,7 +29,6 @@ import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryKeysDAO;
 import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryMailDAO;
 import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryMailDaoAPI;
 import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryMailDaoV2;
-import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryProvider;
 import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryUrlModule;
 import org.apache.james.mailrepository.cassandra.CassandraMailRepositoryUrlStore;
 import org.apache.james.mailrepository.cassandra.MergingCassandraMailRepositoryMailDao;
@@ -60,9 +58,6 @@ public class CassandraMailRepositoryModule extends AbstractModule {
         bind(CassandraMailRepositoryMailDaoAPI.class).to(MergingCassandraMailRepositoryMailDao.class);
         bind(MailRepositoryUrlStore.class).to(CassandraMailRepositoryUrlStore.class);
 
-        Multibinder<MailRepositoryProvider> multibinder = Multibinder.newSetBinder(binder(), MailRepositoryProvider.class);
-        multibinder.addBinding().to(CassandraMailRepositoryProvider.class);
-
         bind(MailStoreRepositoryModule.DefaultItemSupplier.class).toInstance(() -> CASSANDRA_MAILREPOSITORY_DEFAULT_DECLARATION);
 
         Multibinder<CassandraModule> cassandraModuleBinder = Multibinder.newSetBinder(binder(), CassandraModule.class);
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryProvider.java b/server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/GuiceMailRepositoryLoader.java
similarity index 50%
rename from server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryProvider.java
rename to server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/GuiceMailRepositoryLoader.java
index 410c46b..c90ff98 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryProvider.java
+++ b/server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/GuiceMailRepositoryLoader.java
@@ -17,37 +17,37 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailrepository.cassandra;
+package org.apache.james.modules.server;
 
-import javax.inject.Inject;
-
-import org.apache.james.blob.mail.MimeMessageStore;
 import org.apache.james.mailrepository.api.MailRepository;
-import org.apache.james.mailrepository.api.MailRepositoryProvider;
+import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import org.apache.james.mailrepository.memory.MailRepositoryLoader;
+import org.apache.james.utils.ClassName;
+import org.apache.james.utils.GuiceGenericLoader;
+
+import com.google.inject.Inject;
+import com.google.inject.Module;
 
-public class CassandraMailRepositoryProvider implements MailRepositoryProvider {
-    private final CassandraMailRepositoryKeysDAO keysDAO;
-    private final CassandraMailRepositoryCountDAO countDAO;
-    private final CassandraMailRepositoryMailDaoAPI mailDAO;
-    private final MimeMessageStore.Factory mimeMessageStoreFactory;
+public class GuiceMailRepositoryLoader implements MailRepositoryLoader {
+    private final GuiceGenericLoader genericLoader;
 
     @Inject
-    public CassandraMailRepositoryProvider(CassandraMailRepositoryKeysDAO keysDAO, CassandraMailRepositoryCountDAO countDAO,
-                                           CassandraMailRepositoryMailDaoAPI mailDAO, MimeMessageStore.Factory mimeMessageStoreFactory) {
-        this.keysDAO = keysDAO;
-        this.countDAO = countDAO;
-        this.mailDAO = mailDAO;
-        this.mimeMessageStoreFactory = mimeMessageStoreFactory;
+    public GuiceMailRepositoryLoader(GuiceGenericLoader genericLoader) {
+        this.genericLoader = genericLoader;
     }
 
     @Override
-    public String canonicalName() {
-        return CassandraMailRepository.class.getCanonicalName();
-    }
+    public MailRepository load(String fullyQualifiedClassName, MailRepositoryUrl url) throws MailRepositoryStore.MailRepositoryStoreException {
+        try {
+            Module urlModule = binder -> binder.bind(MailRepositoryUrl.class).toInstance(url);
 
-    @Override
-    public MailRepository provide(MailRepositoryUrl url) {
-        return new CassandraMailRepository(url, keysDAO, countDAO, mailDAO, mimeMessageStoreFactory.mimeMessageStore());
+            return genericLoader.<MailRepository>withChildModule(urlModule)
+                .instanciate(new ClassName(fullyQualifiedClassName));
+        } catch (ClassNotFoundException e) {
+            throw new MailRepositoryStore.MailRepositoryStoreException("No Mail Repository found with class name " + fullyQualifiedClassName);
+        } catch (ClassCastException e) {
+            throw new MailRepositoryStore.MailRepositoryStoreException(fullyQualifiedClassName + " is not a MailRepository");
+        }
     }
 }
diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/MailStoreRepositoryModule.java b/server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/MailStoreRepositoryModule.java
index 909b3d8..33a1b99 100644
--- a/server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/MailStoreRepositoryModule.java
+++ b/server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/MailStoreRepositoryModule.java
@@ -25,10 +25,9 @@ import org.apache.commons.configuration2.HierarchicalConfiguration;
 import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.commons.configuration2.tree.ImmutableNode;
 import org.apache.james.lifecycle.api.Startable;
-import org.apache.james.mailrepository.api.MailRepositoryProvider;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
+import org.apache.james.mailrepository.memory.MailRepositoryLoader;
 import org.apache.james.mailrepository.memory.MailRepositoryStoreConfiguration;
-import org.apache.james.mailrepository.memory.MemoryMailRepositoryProvider;
 import org.apache.james.mailrepository.memory.MemoryMailRepositoryStore;
 import org.apache.james.server.core.configuration.ConfigurationProvider;
 import org.apache.james.utils.GuiceProbe;
@@ -55,8 +54,9 @@ public class MailStoreRepositoryModule extends AbstractModule {
         bind(MemoryMailRepositoryStore.class).in(Scopes.SINGLETON);
         bind(MailRepositoryStore.class).to(MemoryMailRepositoryStore.class);
 
-        Multibinder<MailRepositoryProvider> multibinder = Multibinder.newSetBinder(binder(), MailRepositoryProvider.class);
-        multibinder.addBinding().to(MemoryMailRepositoryProvider.class);
+        bind(GuiceMailRepositoryLoader.class).in(Scopes.SINGLETON);
+        bind(MailRepositoryLoader.class).to(GuiceMailRepositoryLoader.class);
+
         Multibinder.newSetBinder(binder(), InitialisationOperation.class).addBinding().to(MailRepositoryStoreModuleInitialisationOperation.class);
         Multibinder.newSetBinder(binder(), GuiceProbe.class).addBinding().to(MailRepositoryProbeImpl.class);
     }
diff --git a/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAMailRepositoryModule.java b/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAMailRepositoryModule.java
index 41257af..51c6587 100644
--- a/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAMailRepositoryModule.java
+++ b/server/container/guice/jpa-common-guice/src/main/java/org/apache/james/modules/data/JPAMailRepositoryModule.java
@@ -20,11 +20,9 @@
 package org.apache.james.modules.data;
 
 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
-import org.apache.james.mailrepository.api.MailRepositoryProvider;
 import org.apache.james.mailrepository.api.MailRepositoryUrlStore;
 import org.apache.james.mailrepository.api.Protocol;
 import org.apache.james.mailrepository.file.FileMailRepository;
-import org.apache.james.mailrepository.file.FileMailRepositoryProvider;
 import org.apache.james.mailrepository.jpa.JPAMailRepositoryUrlStore;
 import org.apache.james.mailrepository.memory.MailRepositoryStoreConfiguration;
 import org.apache.james.modules.server.MailStoreRepositoryModule;
@@ -32,7 +30,6 @@ import org.apache.james.modules.server.MailStoreRepositoryModule;
 import com.google.common.collect.ImmutableList;
 import com.google.inject.AbstractModule;
 import com.google.inject.Scopes;
-import com.google.inject.multibindings.Multibinder;
 
 public class JPAMailRepositoryModule extends AbstractModule {
     private static final MailRepositoryStoreConfiguration.Item FILE_MAILREPOSITORY_DEFAULT_DECLARATION = new MailRepositoryStoreConfiguration.Item(
@@ -47,8 +44,5 @@ public class JPAMailRepositoryModule extends AbstractModule {
         bind(MailRepositoryUrlStore.class).to(JPAMailRepositoryUrlStore.class);
 
         bind(MailStoreRepositoryModule.DefaultItemSupplier.class).toInstance(() -> FILE_MAILREPOSITORY_DEFAULT_DECLARATION);
-
-        Multibinder<MailRepositoryProvider> multibinder = Multibinder.newSetBinder(binder(), MailRepositoryProvider.class);
-        multibinder.addBinding().to(FileMailRepositoryProvider.class);
     }
 }
diff --git a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/data/MemoryDataModule.java b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/data/MemoryDataModule.java
index 2b09793..6192990 100644
--- a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/data/MemoryDataModule.java
+++ b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/data/MemoryDataModule.java
@@ -27,12 +27,10 @@ import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.domainlist.lib.DomainListConfiguration;
 import org.apache.james.domainlist.memory.MemoryDomainList;
 import org.apache.james.lifecycle.api.Startable;
-import org.apache.james.mailrepository.api.MailRepositoryProvider;
 import org.apache.james.mailrepository.api.MailRepositoryUrlStore;
 import org.apache.james.mailrepository.api.Protocol;
 import org.apache.james.mailrepository.memory.MailRepositoryStoreConfiguration;
 import org.apache.james.mailrepository.memory.MemoryMailRepository;
-import org.apache.james.mailrepository.memory.MemoryMailRepositoryProvider;
 import org.apache.james.mailrepository.memory.MemoryMailRepositoryUrlStore;
 import org.apache.james.modules.server.MailStoreRepositoryModule;
 import org.apache.james.rrt.api.RecipientRewriteTable;
@@ -83,9 +81,6 @@ public class MemoryDataModule extends AbstractModule {
         initialisationOperations.addBinding().to(MemoryDomainListInitialisationOperation.class);
 
         bind(MailStoreRepositoryModule.DefaultItemSupplier.class).toInstance(() -> MEMORY_MAILREPOSITORY_DEFAULT_DECLARATION);
-
-        Multibinder<MailRepositoryProvider> multibinder = Multibinder.newSetBinder(binder(), MailRepositoryProvider.class);
-        multibinder.addBinding().to(MemoryMailRepositoryProvider.class);
     }
 
     @Provides
diff --git a/server/mailrepository/mailrepository-memory/src/main/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryProvider.java b/server/data/data-memory/src/main/java/org/apache/james/mailrepository/memory/MailRepositoryLoader.java
similarity index 77%
rename from server/mailrepository/mailrepository-memory/src/main/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryProvider.java
rename to server/data/data-memory/src/main/java/org/apache/james/mailrepository/memory/MailRepositoryLoader.java
index cdde19d..9e24f64 100644
--- a/server/mailrepository/mailrepository-memory/src/main/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryProvider.java
+++ b/server/data/data-memory/src/main/java/org/apache/james/mailrepository/memory/MailRepositoryLoader.java
@@ -20,17 +20,9 @@
 package org.apache.james.mailrepository.memory;
 
 import org.apache.james.mailrepository.api.MailRepository;
-import org.apache.james.mailrepository.api.MailRepositoryProvider;
+import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 
-public class MemoryMailRepositoryProvider implements MailRepositoryProvider {
-    @Override
-    public String canonicalName() {
-        return MemoryMailRepository.class.getCanonicalName();
-    }
-
-    @Override
-    public MailRepository provide(MailRepositoryUrl url) {
-        return new MemoryMailRepository();
-    }
+public interface MailRepositoryLoader {
+    MailRepository load(String fullyQualifiedClassName, MailRepositoryUrl url) throws MailRepositoryStore.MailRepositoryStoreException;
 }
diff --git a/server/data/data-memory/src/main/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryStore.java b/server/data/data-memory/src/main/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryStore.java
index a00714a..61c1069 100644
--- a/server/data/data-memory/src/main/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryStore.java
+++ b/server/data/data-memory/src/main/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryStore.java
@@ -22,7 +22,6 @@ package org.apache.james.mailrepository.memory;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.stream.Stream;
@@ -31,13 +30,11 @@ import javax.inject.Inject;
 
 import org.apache.commons.configuration2.CombinedConfiguration;
 import org.apache.commons.configuration2.HierarchicalConfiguration;
-import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.commons.configuration2.tree.ImmutableNode;
 import org.apache.james.lifecycle.api.Configurable;
 import org.apache.james.lifecycle.api.Startable;
 import org.apache.james.mailrepository.api.MailRepository;
 import org.apache.james.mailrepository.api.MailRepositoryPath;
-import org.apache.james.mailrepository.api.MailRepositoryProvider;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.mailrepository.api.MailRepositoryUrlStore;
@@ -47,24 +44,25 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.github.fge.lambdas.Throwing;
+import com.github.fge.lambdas.functions.ThrowingFunction;
 
 public class MemoryMailRepositoryStore implements MailRepositoryStore, Startable {
     private static final Logger LOGGER = LoggerFactory.getLogger(MemoryMailRepositoryStore.class);
 
     private final MailRepositoryUrlStore urlStore;
-    private final Set<MailRepositoryProvider> mailRepositories;
     private final ConcurrentMap<MailRepositoryUrl, MailRepository> destinationToRepositoryAssociations;
-    private final Map<Protocol, MailRepositoryProvider> protocolToRepositoryProvider;
+    private final Map<Protocol, String> protocolToClass;
+    private final MailRepositoryLoader mailRepositoryLoader;
     private final Map<Protocol, HierarchicalConfiguration<ImmutableNode>> perProtocolMailRepositoryDefaultConfiguration;
     private final MailRepositoryStoreConfiguration configuration;
 
     @Inject
-    public MemoryMailRepositoryStore(MailRepositoryUrlStore urlStore, Set<MailRepositoryProvider> mailRepositories, MailRepositoryStoreConfiguration configuration) {
+    public MemoryMailRepositoryStore(MailRepositoryUrlStore urlStore, MailRepositoryLoader mailRepositoryLoader, MailRepositoryStoreConfiguration configuration) {
         this.urlStore = urlStore;
-        this.mailRepositories = mailRepositories;
+        this.mailRepositoryLoader = mailRepositoryLoader;
         this.configuration = configuration;
         this.destinationToRepositoryAssociations = new ConcurrentHashMap<>();
-        this.protocolToRepositoryProvider = new HashMap<>();
+        this.protocolToClass = new HashMap<>();
         this.perProtocolMailRepositoryDefaultConfiguration = new HashMap<>();
     }
 
@@ -76,16 +74,9 @@ public class MemoryMailRepositoryStore implements MailRepositoryStore, Startable
         }
     }
 
-    private void initEntry(MailRepositoryStoreConfiguration.Item item) throws ConfigurationException {
-        String className = item.getClassFqdn();
-
-        MailRepositoryProvider usedMailRepository = mailRepositories.stream()
-            .filter(mailRepositoryProvider -> mailRepositoryProvider.canonicalName().equals(className))
-            .findAny()
-            .orElseThrow(() -> new ConfigurationException("MailRepository " + className + " has not been registered"));
-
+    private void initEntry(MailRepositoryStoreConfiguration.Item item) {
         for (Protocol protocol : item.getProtocols()) {
-            protocolToRepositoryProvider.put(protocol, usedMailRepository);
+            protocolToClass.put(protocol, item.getClassFqdn());
             perProtocolMailRepositoryDefaultConfiguration.put(protocol, item.getConfiguration());
         }
     }
@@ -148,8 +139,12 @@ public class MemoryMailRepositoryStore implements MailRepositoryStore, Startable
 
     private MailRepository retrieveMailRepository(MailRepositoryUrl mailRepositoryUrl) throws MailRepositoryStoreException {
         Protocol protocol = mailRepositoryUrl.getProtocol();
-        return Optional.ofNullable(protocolToRepositoryProvider.get(protocol))
-            .orElseThrow(() -> new MailRepositoryStoreException("No Mail Repository associated with " + protocol.getValue()))
-            .provide(mailRepositoryUrl);
+        Optional<String> fullyQualifiedClass = Optional.ofNullable(protocolToClass.get(protocol));
+
+        ThrowingFunction<String, MailRepository> fqcnToMailRepository = className -> mailRepositoryLoader.load(className, mailRepositoryUrl);
+
+        return fullyQualifiedClass
+            .map(Throwing.function(fqcnToMailRepository).sneakyThrow())
+            .orElseThrow(() -> new MailRepositoryStoreException("No Mail Repository associated with " + protocol.getValue()));
     }
 }
diff --git a/server/data/data-memory/src/test/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryStoreTest.java b/server/data/data-memory/src/test/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryStoreTest.java
index 007547e..b430595 100644
--- a/server/data/data-memory/src/test/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryStoreTest.java
+++ b/server/data/data-memory/src/test/java/org/apache/james/mailrepository/memory/MemoryMailRepositoryStoreTest.java
@@ -25,12 +25,12 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import java.time.Duration;
 
 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
-import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.mailrepository.api.MailRepository;
 import org.apache.james.mailrepository.api.MailRepositoryPath;
 import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import org.apache.james.mailrepository.api.Protocol;
 import org.apache.james.server.core.configuration.Configuration;
 import org.apache.james.server.core.configuration.FileConfigurationProvider;
 import org.apache.james.server.core.filesystem.FileSystemImpl;
@@ -39,8 +39,6 @@ import org.apache.mailet.base.test.FakeMail;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.google.common.collect.Sets;
-
 public class MemoryMailRepositoryStoreTest {
     private static final MailRepositoryUrl MEMORY1_REPO = MailRepositoryUrl.from("memory1://repo");
     private static final MailRepositoryUrl UNKNOWN_PROTOCOL_REPO = MailRepositoryUrl.from("toto://repo");
@@ -49,12 +47,14 @@ public class MemoryMailRepositoryStoreTest {
 
     private MemoryMailRepositoryUrlStore urlStore;
 
+    private TestingMailRepositoryLoader loader;
     private MemoryMailRepositoryStore repositoryStore;
     private FileSystemImpl fileSystem;
     private Configuration configuration;
 
     @Before
     public void setUp() throws Exception {
+        loader = new TestingMailRepositoryLoader();
         configuration = Configuration.builder()
             .workingDirectory("../")
             .configurationFromClasspath()
@@ -65,10 +65,7 @@ public class MemoryMailRepositoryStoreTest {
         MailRepositoryStoreConfiguration storeConfiguration = MailRepositoryStoreConfiguration.parse(
             new FileConfigurationProvider(fileSystem, configuration).getConfiguration("mailrepositorystore"));
 
-        repositoryStore = new MemoryMailRepositoryStore(urlStore, Sets.newHashSet(
-                new MemoryMailRepositoryProvider(),
-                new MemoryMailRepositoryProvider()),
-            storeConfiguration);
+        repositoryStore = new MemoryMailRepositoryStore(urlStore, loader, storeConfiguration);
         repositoryStore.init();
     }
 
@@ -100,19 +97,20 @@ public class MemoryMailRepositoryStoreTest {
         MailRepositoryStoreConfiguration storeConfiguration = MailRepositoryStoreConfiguration.parse(
             new FileConfigurationProvider(fileSystem, configuration).getConfiguration("fakemailrepositorystore"));
 
-        repositoryStore = new MemoryMailRepositoryStore(urlStore, Sets.newHashSet(
-            new MemoryMailRepositoryProvider()), storeConfiguration);
+        repositoryStore = new MemoryMailRepositoryStore(urlStore, loader, storeConfiguration);
+
+        repositoryStore.init();
 
-        assertThatThrownBy(() -> repositoryStore.init())
-            .isInstanceOf(ConfigurationException.class);
+        assertThatThrownBy(() -> repositoryStore.select(MailRepositoryUrl.fromPathAndProtocol(
+            new Protocol("memory"), MailRepositoryPath.from("/var/will/fail"))))
+            .isInstanceOf(MailRepositoryStore.MailRepositoryStoreException.class);
     }
 
     @Test
     public void configureShouldNotThrowOnEmptyConfiguration() throws Exception {
         MailRepositoryStoreConfiguration configuration = MailRepositoryStoreConfiguration.parse(new BaseHierarchicalConfiguration());
 
-        repositoryStore = new MemoryMailRepositoryStore(urlStore, Sets.newHashSet(
-            new MemoryMailRepositoryProvider()), configuration);
+        repositoryStore = new MemoryMailRepositoryStore(urlStore, loader, configuration);
 
         repositoryStore.init();
     }
diff --git a/server/data/data-file/src/main/java/org/apache/james/mailrepository/file/FileMailRepositoryProvider.java b/server/data/data-memory/src/test/java/org/apache/james/mailrepository/memory/TestingMailRepositoryLoader.java
similarity index 63%
rename from server/data/data-file/src/main/java/org/apache/james/mailrepository/file/FileMailRepositoryProvider.java
rename to server/data/data-memory/src/test/java/org/apache/james/mailrepository/memory/TestingMailRepositoryLoader.java
index b8d52ed..93db1f9 100644
--- a/server/data/data-file/src/main/java/org/apache/james/mailrepository/file/FileMailRepositoryProvider.java
+++ b/server/data/data-memory/src/test/java/org/apache/james/mailrepository/memory/TestingMailRepositoryLoader.java
@@ -17,33 +17,18 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailrepository.file;
+package org.apache.james.mailrepository.memory;
 
-import javax.inject.Inject;
-
-import org.apache.james.filesystem.api.FileSystem;
 import org.apache.james.mailrepository.api.MailRepository;
-import org.apache.james.mailrepository.api.MailRepositoryProvider;
+import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
 
-public class FileMailRepositoryProvider implements MailRepositoryProvider {
-
-    private final FileSystem fileSystem;
-
-    @Inject
-    public FileMailRepositoryProvider(FileSystem fileSystem) {
-        this.fileSystem = fileSystem;
-    }
-
-    @Override
-    public String canonicalName() {
-        return FileMailRepository.class.getCanonicalName();
-    }
-
+public class TestingMailRepositoryLoader implements MailRepositoryLoader {
     @Override
-    public MailRepository provide(MailRepositoryUrl url) {
-        FileMailRepository fileMailRepository = new FileMailRepository();
-        fileMailRepository.setFileSystem(fileSystem);
-        return fileMailRepository;
+    public MailRepository load(String fullyQualifiedClassName, MailRepositoryUrl url) throws MailRepositoryStore.MailRepositoryStoreException {
+        if (fullyQualifiedClassName.equals(MemoryMailRepository.class.getCanonicalName())) {
+            return new MemoryMailRepository();
+        }
+        throw new MailRepositoryStore.MailRepositoryStoreException(fullyQualifiedClassName + " is not supported");
     }
 }
diff --git a/server/mailet/mailets/pom.xml b/server/mailet/mailets/pom.xml
index 8ac7d06..b1c30bf 100644
--- a/server/mailet/mailets/pom.xml
+++ b/server/mailet/mailets/pom.xml
@@ -127,6 +127,12 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-data-memory</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-dnsservice-api</artifactId>
         </dependency>
         <dependency>
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
index 34e5a02..ee21b37 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java
@@ -36,9 +36,9 @@ import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.mailrepository.api.Protocol;
 import org.apache.james.mailrepository.memory.MailRepositoryStoreConfiguration;
 import org.apache.james.mailrepository.memory.MemoryMailRepository;
-import org.apache.james.mailrepository.memory.MemoryMailRepositoryProvider;
 import org.apache.james.mailrepository.memory.MemoryMailRepositoryStore;
 import org.apache.james.mailrepository.memory.MemoryMailRepositoryUrlStore;
+import org.apache.james.mailrepository.memory.TestingMailRepositoryLoader;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.FakeMail;
@@ -47,7 +47,6 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Sets;
 
 class ToSenderDomainRepositoryTest {
 
@@ -75,7 +74,7 @@ class ToSenderDomainRepositoryTest {
                 MemoryMailRepository.class.getName(),
                 new BaseHierarchicalConfiguration()));
 
-        mailRepositoryStore = new MemoryMailRepositoryStore(urlStore, Sets.newHashSet(new MemoryMailRepositoryProvider()), configuration);
+        mailRepositoryStore = new MemoryMailRepositoryStore(urlStore, new TestingMailRepositoryLoader(), configuration);
         mailRepositoryStore.init();
     }
 
diff --git a/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryProvider.java b/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryProvider.java
deleted file mode 100644
index 18ffa96..0000000
--- a/server/mailrepository/mailrepository-api/src/main/java/org/apache/james/mailrepository/api/MailRepositoryProvider.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/****************************************************************
- * 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.mailrepository.api;
-
-public interface MailRepositoryProvider {
-
-    String canonicalName();
-
-    MailRepository provide(MailRepositoryUrl url);
-}
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
index 08f4f99..277c39d 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
@@ -22,11 +22,13 @@ package org.apache.james.mailrepository.cassandra;
 import java.util.Collection;
 import java.util.Iterator;
 
+import javax.inject.Inject;
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
 
 import org.apache.james.blob.api.Store;
 import org.apache.james.blob.mail.MimeMessagePartsId;
+import org.apache.james.blob.mail.MimeMessageStore;
 import org.apache.james.mailrepository.api.MailKey;
 import org.apache.james.mailrepository.api.MailRepository;
 import org.apache.james.mailrepository.api.MailRepositoryUrl;
@@ -36,16 +38,22 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraMailRepository implements MailRepository {
-
     private final MailRepositoryUrl url;
     private final CassandraMailRepositoryKeysDAO keysDAO;
     private final CassandraMailRepositoryCountDAO countDAO;
     private final CassandraMailRepositoryMailDaoAPI mailDAO;
     private final Store<MimeMessage, MimeMessagePartsId> mimeMessageStore;
 
-    public CassandraMailRepository(MailRepositoryUrl url, CassandraMailRepositoryKeysDAO keysDAO,
-                                   CassandraMailRepositoryCountDAO countDAO, CassandraMailRepositoryMailDaoAPI mailDAO,
-                                   Store<MimeMessage, MimeMessagePartsId> mimeMessageStore) {
+    @Inject
+    CassandraMailRepository(MailRepositoryUrl url, CassandraMailRepositoryKeysDAO keysDAO,
+                            CassandraMailRepositoryCountDAO countDAO, CassandraMailRepositoryMailDaoAPI mailDAO,
+                            MimeMessageStore.Factory mimeMessageStoreFactory) {
+        this(url, keysDAO, countDAO, mailDAO, mimeMessageStoreFactory.mimeMessageStore());
+    }
+
+    CassandraMailRepository(MailRepositoryUrl url, CassandraMailRepositoryKeysDAO keysDAO,
+                            CassandraMailRepositoryCountDAO countDAO, CassandraMailRepositoryMailDaoAPI mailDAO,
+                            Store<MimeMessage, MimeMessagePartsId> mimeMessageStore) {
         this.url = url;
         this.keysDAO = keysDAO;
         this.countDAO = countDAO;
diff --git a/server/protocols/protocols-smtp/pom.xml b/server/protocols/protocols-smtp/pom.xml
index 88eae80..bf3968b 100644
--- a/server/protocols/protocols-smtp/pom.xml
+++ b/server/protocols/protocols-smtp/pom.xml
@@ -62,6 +62,12 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-data-memory</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-dnsservice-api</artifactId>
         </dependency>
         <dependency>
diff --git a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
index 406f888..e688f48 100644
--- a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
+++ b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
@@ -54,9 +54,9 @@ import org.apache.james.mailrepository.api.MailRepositoryStore;
 import org.apache.james.mailrepository.api.Protocol;
 import org.apache.james.mailrepository.memory.MailRepositoryStoreConfiguration;
 import org.apache.james.mailrepository.memory.MemoryMailRepository;
-import org.apache.james.mailrepository.memory.MemoryMailRepositoryProvider;
 import org.apache.james.mailrepository.memory.MemoryMailRepositoryStore;
 import org.apache.james.mailrepository.memory.MemoryMailRepositoryUrlStore;
+import org.apache.james.mailrepository.memory.TestingMailRepositoryLoader;
 import org.apache.james.metrics.api.Metric;
 import org.apache.james.protocols.api.utils.ProtocolServerUtils;
 import org.apache.james.protocols.lib.mock.MockProtocolHandlerLoader;
@@ -82,7 +82,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Sets;
 
 public class SMTPServerTest {
 
@@ -210,7 +209,7 @@ public class SMTPServerTest {
                 MemoryMailRepository.class.getName(),
                 new BaseHierarchicalConfiguration()));
 
-        mailRepositoryStore = new MemoryMailRepositoryStore(urlStore, Sets.newHashSet(new MemoryMailRepositoryProvider()), configuration);
+        mailRepositoryStore = new MemoryMailRepositoryStore(urlStore, new TestingMailRepositoryLoader(), configuration);
         mailRepositoryStore.init();
     }
 
diff --git a/server/protocols/webadmin/webadmin-mailrepository/pom.xml b/server/protocols/webadmin/webadmin-mailrepository/pom.xml
index f6126ce..e52a0bb 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailrepository/pom.xml
@@ -58,6 +58,12 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-data-memory</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-queue-api</artifactId>
         </dependency>
         <dependency>
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
index 8ad526b..967b260 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
@@ -56,9 +56,9 @@ import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.mailrepository.api.Protocol;
 import org.apache.james.mailrepository.memory.MailRepositoryStoreConfiguration;
 import org.apache.james.mailrepository.memory.MemoryMailRepository;
-import org.apache.james.mailrepository.memory.MemoryMailRepositoryProvider;
 import org.apache.james.mailrepository.memory.MemoryMailRepositoryStore;
 import org.apache.james.mailrepository.memory.MemoryMailRepositoryUrlStore;
+import org.apache.james.mailrepository.memory.TestingMailRepositoryLoader;
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.queue.api.ManageableMailQueue;
 import org.apache.james.queue.api.RawMailQueueItemDecoratorFactory;
@@ -86,7 +86,6 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Sets;
 
 import io.restassured.RestAssured;
 import io.restassured.builder.RequestSpecBuilder;
@@ -1776,7 +1775,7 @@ public class MailRepositoriesRoutesTest {
                 ImmutableList.of(new Protocol("other")),
                 MemoryMailRepository.class.getName(),
                 new BaseHierarchicalConfiguration()));
-        mailRepositoryStore = new MemoryMailRepositoryStore(urlStore, Sets.newHashSet(new MemoryMailRepositoryProvider()), configuration);
+        mailRepositoryStore = new MemoryMailRepositoryStore(urlStore, new TestingMailRepositoryLoader(), configuration);
 
         mailRepositoryStore.init();
     }
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingServiceTest.java b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingServiceTest.java
index e78b819..4c6dca1 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingServiceTest.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/service/ReprocessingServiceTest.java
@@ -33,9 +33,9 @@ import org.apache.james.mailrepository.api.MailRepositoryUrl;
 import org.apache.james.mailrepository.api.Protocol;
 import org.apache.james.mailrepository.memory.MailRepositoryStoreConfiguration;
 import org.apache.james.mailrepository.memory.MemoryMailRepository;
-import org.apache.james.mailrepository.memory.MemoryMailRepositoryProvider;
 import org.apache.james.mailrepository.memory.MemoryMailRepositoryStore;
 import org.apache.james.mailrepository.memory.MemoryMailRepositoryUrlStore;
+import org.apache.james.mailrepository.memory.TestingMailRepositoryLoader;
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.queue.api.ManageableMailQueue;
 import org.apache.james.queue.api.RawMailQueueItemDecoratorFactory;
@@ -47,7 +47,6 @@ import org.junit.Test;
 import com.github.fge.lambdas.Throwing;
 import com.github.fge.lambdas.consumers.ConsumerChainer;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Sets;
 
 public class ReprocessingServiceTest {
     private static final String MEMORY_PROTOCOL = "memory";
@@ -187,7 +186,7 @@ public class ReprocessingServiceTest {
                 MemoryMailRepository.class.getName(),
                 new BaseHierarchicalConfiguration()));
 
-        MemoryMailRepositoryStore mailRepositoryStore = new MemoryMailRepositoryStore(urlStore, Sets.newHashSet(new MemoryMailRepositoryProvider()), configuration);
+        MemoryMailRepositoryStore mailRepositoryStore = new MemoryMailRepositoryStore(urlStore, new TestingMailRepositoryLoader(), configuration);
         mailRepositoryStore.init();
         return mailRepositoryStore;
     }


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


[james-project] 02/03: JAMES-2563 Upgrade to ElasticSearch client 6.4.3

Posted by bt...@apache.org.
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 066c6d98a1961190f7a3693aa080e1d8eb815625
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Sep 25 13:57:31 2019 +0700

    JAMES-2563 Upgrade to ElasticSearch client 6.4.3
    
    This enables health checks as part of the Rest High level client API,
    avoiding the need of low level hacky queries.
---
 backends-common/elasticsearch/pom.xml              |  2 +-
 .../james/backends/es/ElasticSearchIndexer.java    |  6 ++++--
 .../james/backends/es/IndexCreationFactory.java    |  8 +++++---
 .../james/backends/es/NodeMappingFactory.java      |  6 +++++-
 .../es/ClientProviderImplConnectionTest.java       |  4 +++-
 .../james/backends/es/DockerElasticSearch.java     |  3 +++
 .../james/backends/es/DockerElasticSearchRule.java |  2 +-
 .../backends/es/ElasticSearchIndexerTest.java      | 24 ++++++++++++++--------
 .../backends/es/search/ScrolledSearchTest.java     | 23 +++++++++++++--------
 .../elasticsearch/ElasticSearchQuotaSearcher.java  |  3 ++-
 10 files changed, 55 insertions(+), 26 deletions(-)

diff --git a/backends-common/elasticsearch/pom.xml b/backends-common/elasticsearch/pom.xml
index f2ad34f..ea60bba 100644
--- a/backends-common/elasticsearch/pom.xml
+++ b/backends-common/elasticsearch/pom.xml
@@ -74,7 +74,7 @@
         <dependency>
             <groupId>org.elasticsearch.client</groupId>
             <artifactId>elasticsearch-rest-high-level-client</artifactId>
-            <version>6.3.2</version>
+            <version>6.4.3</version>
             <exclusions>
                 <exclusion>
                     <groupId>commons-logging</groupId>
diff --git a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchIndexer.java b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchIndexer.java
index 1006232..bc586a4 100644
--- a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchIndexer.java
+++ b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchIndexer.java
@@ -29,6 +29,7 @@ import org.elasticsearch.action.delete.DeleteRequest;
 import org.elasticsearch.action.index.IndexRequest;
 import org.elasticsearch.action.index.IndexResponse;
 import org.elasticsearch.action.update.UpdateRequest;
+import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.elasticsearch.common.ValidationException;
 import org.elasticsearch.common.xcontent.XContentType;
@@ -72,7 +73,8 @@ public class ElasticSearchIndexer {
             new IndexRequest(aliasName.getValue())
                 .type(NodeMappingFactory.DEFAULT_MAPPING_NAME)
                 .id(id)
-                .source(content, XContentType.JSON));
+                .source(content, XContentType.JSON),
+            RequestOptions.DEFAULT);
     }
 
     public Optional<BulkResponse> update(List<UpdatedRepresentation> updatedDocumentParts) throws IOException {
@@ -84,7 +86,7 @@ public class ElasticSearchIndexer {
                     NodeMappingFactory.DEFAULT_MAPPING_NAME,
                     updatedDocumentPart.getId())
                 .doc(updatedDocumentPart.getUpdatedDocumentPart(), XContentType.JSON)));
-            return Optional.of(client.bulk(request));
+            return Optional.of(client.bulk(request, RequestOptions.DEFAULT));
         } catch (ValidationException e) {
             LOGGER.warn("Error while updating index", e);
             return Optional.empty();
diff --git a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/IndexCreationFactory.java b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/IndexCreationFactory.java
index 9096fb8..18bfbf8 100644
--- a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/IndexCreationFactory.java
+++ b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/IndexCreationFactory.java
@@ -30,6 +30,7 @@ import org.elasticsearch.ElasticsearchStatusException;
 import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
 import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
 import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
+import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.slf4j.Logger;
@@ -97,13 +98,14 @@ public class IndexCreationFactory {
                         new IndicesAliasesRequest().addAliasAction(
                             new AliasActions(AliasActions.Type.ADD)
                                 .index(indexName.getValue())
-                                .alias(aliasName.getValue())));
+                                .alias(aliasName.getValue())),
+                        RequestOptions.DEFAULT);
             }
         }
 
         private boolean aliasExist(RestHighLevelClient client, AliasName aliasName) throws IOException {
             return client.indices()
-                .existsAlias(new GetAliasesRequest().aliases(aliasName.getValue()));
+                .existsAlias(new GetAliasesRequest().aliases(aliasName.getValue()), RequestOptions.DEFAULT);
         }
 
         private void createIndexIfNeeded(RestHighLevelClient client, IndexName indexName, XContentBuilder settings) throws IOException {
@@ -111,7 +113,7 @@ public class IndexCreationFactory {
                 client.indices()
                     .create(
                         new CreateIndexRequest(indexName.getValue())
-                            .source(settings));
+                            .source(settings), RequestOptions.DEFAULT);
             } catch (ElasticsearchStatusException exception) {
                 if (exception.getMessage().contains(INDEX_ALREADY_EXISTS_EXCEPTION_MESSAGE)) {
                     LOGGER.info("Index [{}] already exist", indexName);
diff --git a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/NodeMappingFactory.java b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/NodeMappingFactory.java
index 880d9ad..2dfa375 100644
--- a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/NodeMappingFactory.java
+++ b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/NodeMappingFactory.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 
 import org.apache.http.HttpStatus;
 import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
+import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.ResponseException;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -59,6 +60,8 @@ public class NodeMappingFactory {
         return client;
     }
 
+    // ElasticSearch 6.3.2 does not support field master_timeout that is set up by 6.4.3 REST client when relying on getMapping
+    @SuppressWarnings("deprecation")
     public static boolean mappingAlreadyExist(RestHighLevelClient client, IndexName indexName) throws IOException {
         try {
             client.getLowLevelClient().performRequest("GET", indexName.getValue() + "/_mapping/" + NodeMappingFactory.DEFAULT_MAPPING_NAME);
@@ -75,7 +78,8 @@ public class NodeMappingFactory {
         client.indices().putMapping(
             new PutMappingRequest(indexName.getValue())
                 .type(NodeMappingFactory.DEFAULT_MAPPING_NAME)
-                .source(mappingsSources));
+                .source(mappingsSources),
+            RequestOptions.DEFAULT);
     }
 
 }
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionTest.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionTest.java
index 3ae7449..042cbfd 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionTest.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ClientProviderImplConnectionTest.java
@@ -26,6 +26,7 @@ import org.apache.james.util.docker.DockerContainer;
 import org.apache.james.util.docker.Images;
 import org.awaitility.Awaitility;
 import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.search.builder.SearchSourceBuilder;
@@ -97,7 +98,8 @@ public class ClientProviderImplConnectionTest {
         try (RestHighLevelClient client = clientProvider.get()) {
             client.search(
                 new SearchRequest()
-                    .source(new SearchSourceBuilder().query(QueryBuilders.existsQuery("any"))));
+                    .source(new SearchSourceBuilder().query(QueryBuilders.existsQuery("any"))),
+                RequestOptions.DEFAULT);
             return true;
         } catch (Exception e) {
             LOGGER.info("Caught exception while trying to connect", e);
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java
index ffff560..9398dae 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java
@@ -19,6 +19,9 @@
 
 package org.apache.james.backends.es;
 
+import java.time.Duration;
+import java.util.Optional;
+
 import org.apache.http.HttpStatus;
 import org.apache.james.util.Host;
 import org.apache.james.util.docker.DockerContainer;
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearchRule.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearchRule.java
index a7de917..0f0d3d2 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearchRule.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearchRule.java
@@ -26,7 +26,7 @@ public class DockerElasticSearchRule extends ExternalResource {
     private final DockerElasticSearch dockerElasticSearch = DockerElasticSearchSingleton.INSTANCE;
 
     @Override
-    protected void before() throws Throwable {
+    protected void before() {
         dockerElasticSearch.start();
     }
 
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchIndexerTest.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchIndexerTest.java
index 08e4e4f..ba4e4f7 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchIndexerTest.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchIndexerTest.java
@@ -31,6 +31,7 @@ import org.awaitility.Duration;
 import org.awaitility.core.ConditionFactory;
 import org.elasticsearch.action.search.SearchRequest;
 import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.search.builder.SearchSourceBuilder;
@@ -82,7 +83,8 @@ public class ElasticSearchIndexerTest {
         
         SearchResponse searchResponse = client.search(
             new SearchRequest(INDEX_NAME.getValue())
-                .source(new SearchSourceBuilder().query(QueryBuilders.matchQuery("message", "trying"))));
+                .source(new SearchSourceBuilder().query(QueryBuilders.matchQuery("message", "trying"))),
+            RequestOptions.DEFAULT);
         assertThat(searchResponse.getHits().getTotalHits()).isEqualTo(1);
     }
     
@@ -106,12 +108,14 @@ public class ElasticSearchIndexerTest {
 
         SearchResponse searchResponse = client.search(
             new SearchRequest(INDEX_NAME.getValue())
-                .source(new SearchSourceBuilder().query(QueryBuilders.matchQuery("message", "mastering"))));
+                .source(new SearchSourceBuilder().query(QueryBuilders.matchQuery("message", "mastering"))),
+            RequestOptions.DEFAULT);
         assertThat(searchResponse.getHits().getTotalHits()).isEqualTo(1);
 
         SearchResponse searchResponse2 = client.search(
             new SearchRequest(INDEX_NAME.getValue())
-                .source(new SearchSourceBuilder().query(QueryBuilders.matchQuery("field", "unchanged"))));
+                .source(new SearchSourceBuilder().query(QueryBuilders.matchQuery("field", "unchanged"))),
+            RequestOptions.DEFAULT);
         assertThat(searchResponse2.getHits().getTotalHits()).isEqualTo(1);
     }
 
@@ -153,7 +157,8 @@ public class ElasticSearchIndexerTest {
         CALMLY_AWAIT.atMost(Duration.TEN_SECONDS)
             .until(() -> client.search(
                     new SearchRequest(INDEX_NAME.getValue())
-                        .source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())))
+                        .source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())),
+                    RequestOptions.DEFAULT)
                 .getHits().getTotalHits() == 0);
     }
 
@@ -180,8 +185,9 @@ public class ElasticSearchIndexerTest {
         
         CALMLY_AWAIT.atMost(Duration.TEN_SECONDS)
             .until(() -> client.search(
-                new SearchRequest(INDEX_NAME.getValue())
-                    .source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())))
+                    new SearchRequest(INDEX_NAME.getValue())
+                        .source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())),
+                    RequestOptions.DEFAULT)
                 .getHits().getTotalHits() == 1);
     }
     
@@ -198,7 +204,8 @@ public class ElasticSearchIndexerTest {
         
         SearchResponse searchResponse = client.search(
             new SearchRequest(INDEX_NAME.getValue())
-                .source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())));
+                .source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())),
+            RequestOptions.DEFAULT);
         assertThat(searchResponse.getHits().getTotalHits()).isEqualTo(0);
     }
 
@@ -225,7 +232,8 @@ public class ElasticSearchIndexerTest {
 
         SearchResponse searchResponse = client.search(
             new SearchRequest(INDEX_NAME.getValue())
-                .source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())));
+                .source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())),
+            RequestOptions.DEFAULT);
         assertThat(searchResponse.getHits().getTotalHits()).isEqualTo(1);
     }
     
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/search/ScrolledSearchTest.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/search/ScrolledSearchTest.java
index 49549af..6cd3e45 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/search/ScrolledSearchTest.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/search/ScrolledSearchTest.java
@@ -34,6 +34,7 @@ import org.awaitility.Duration;
 import org.awaitility.core.ConditionFactory;
 import org.elasticsearch.action.index.IndexRequest;
 import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.index.query.QueryBuilders;
@@ -73,7 +74,7 @@ public class ScrolledSearchTest {
     }
 
     @Test
-    public void scrollIterableShouldWorkWhenEmpty() throws Exception {
+    public void scrollIterableShouldWorkWhenEmpty() {
         SearchRequest searchRequest = new SearchRequest(INDEX_NAME.getValue())
             .scroll(TIMEOUT)
             .source(new SearchSourceBuilder()
@@ -90,7 +91,8 @@ public class ScrolledSearchTest {
         client.index(new IndexRequest(INDEX_NAME.getValue())
                 .type(NodeMappingFactory.DEFAULT_MAPPING_NAME)
                 .id(id)
-                .source(MESSAGE, "Sample message"));
+                .source(MESSAGE, "Sample message"),
+            RequestOptions.DEFAULT);
 
         elasticSearch.awaitForElasticSearch();
         WAIT_CONDITION.untilAsserted(() -> hasIdsInIndex(client, id));
@@ -112,13 +114,15 @@ public class ScrolledSearchTest {
         client.index(new IndexRequest(INDEX_NAME.getValue())
                 .type(NodeMappingFactory.DEFAULT_MAPPING_NAME)
                 .id(id1)
-                .source(MESSAGE, "Sample message"));
+                .source(MESSAGE, "Sample message"),
+            RequestOptions.DEFAULT);
 
         String id2 = "2";
         client.index(new IndexRequest(INDEX_NAME.getValue())
                 .type(NodeMappingFactory.DEFAULT_MAPPING_NAME)
                 .id(id2)
-                .source(MESSAGE, "Sample message"));
+                .source(MESSAGE, "Sample message"),
+            RequestOptions.DEFAULT);
 
         elasticSearch.awaitForElasticSearch();
         WAIT_CONDITION.untilAsserted(() -> hasIdsInIndex(client, id1, id2));
@@ -140,19 +144,22 @@ public class ScrolledSearchTest {
         client.index(new IndexRequest(INDEX_NAME.getValue())
                 .type(NodeMappingFactory.DEFAULT_MAPPING_NAME)
                 .id(id1)
-                .source(MESSAGE, "Sample message"));
+                .source(MESSAGE, "Sample message"),
+            RequestOptions.DEFAULT);
 
         String id2 = "2";
         client.index(new IndexRequest(INDEX_NAME.getValue())
                 .type(NodeMappingFactory.DEFAULT_MAPPING_NAME)
                 .id(id2)
-                .source(MESSAGE, "Sample message"));
+                .source(MESSAGE, "Sample message"),
+            RequestOptions.DEFAULT);
 
         String id3 = "3";
         client.index(new IndexRequest(INDEX_NAME.getValue())
                 .type(NodeMappingFactory.DEFAULT_MAPPING_NAME)
                 .id(id3)
-                .source(MESSAGE, "Sample message"));
+                .source(MESSAGE, "Sample message"),
+            RequestOptions.DEFAULT);
 
         elasticSearch.awaitForElasticSearch();
         WAIT_CONDITION.untilAsserted(() -> hasIdsInIndex(client, id1, id2, id3));
@@ -174,7 +181,7 @@ public class ScrolledSearchTest {
             .source(new SearchSourceBuilder()
                 .query(QueryBuilders.matchAllQuery()));
 
-        SearchHit[] hits = client.search(searchRequest)
+        SearchHit[] hits = client.search(searchRequest, RequestOptions.DEFAULT)
             .getHits()
             .getHits();
 
diff --git a/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/ElasticSearchQuotaSearcher.java b/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/ElasticSearchQuotaSearcher.java
index 7c02032..1a7e314 100644
--- a/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/ElasticSearchQuotaSearcher.java
+++ b/mailbox/plugin/quota-search-elasticsearch/src/main/java/org/apache/james/quota/search/elasticsearch/ElasticSearchQuotaSearcher.java
@@ -34,6 +34,7 @@ import org.apache.james.core.User;
 import org.apache.james.quota.search.QuotaQuery;
 import org.apache.james.quota.search.QuotaSearcher;
 import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.client.RequestOptions;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.search.SearchHit;
@@ -88,7 +89,7 @@ public class ElasticSearchQuotaSearcher implements QuotaSearcher {
             .types(NodeMappingFactory.DEFAULT_MAPPING_NAME)
             .source(searchSourceBuilder);
 
-        return Arrays.stream(client.search(searchRequest)
+        return Arrays.stream(client.search(searchRequest, RequestOptions.DEFAULT)
             .getHits()
             .getHits());
     }


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


[james-project] 03/03: JAMES-2563 Implement ElasticSearch healthCheck

Posted by bt...@apache.org.
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 e0cfb68a2a5a4a676e7402035ce21e8e18b033a3
Author: Jeroen Reijn <j....@gmail.com>
AuthorDate: Tue Oct 16 22:12:59 2018 +0200

    JAMES-2563 Implement ElasticSearch healthCheck
---
 backends-common/elasticsearch/pom.xml              |  4 +
 .../backends/es/ElasticSearchHealthCheck.java      | 90 ++++++++++++++++++++++
 .../james/backends/es/DockerElasticSearch.java     | 15 +++-
 .../es/ElasticSearchHealthCheckConnectionTest.java | 44 ++++++++---
 .../backends/es/ElasticSearchHealthCheckTest.java  | 79 +++++++++++++++++++
 .../modules/mailbox/ElasticSearchClientModule.java | 23 ++++++
 6 files changed, 244 insertions(+), 11 deletions(-)

diff --git a/backends-common/elasticsearch/pom.xml b/backends-common/elasticsearch/pom.xml
index ea60bba..911297c 100644
--- a/backends-common/elasticsearch/pom.xml
+++ b/backends-common/elasticsearch/pom.xml
@@ -30,6 +30,10 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
diff --git a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchHealthCheck.java b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchHealthCheck.java
new file mode 100644
index 0000000..1305420
--- /dev/null
+++ b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchHealthCheck.java
@@ -0,0 +1,90 @@
+/****************************************************************
+ * 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.backends.es;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.apache.commons.lang3.NotImplementedException;
+import org.apache.james.core.healthcheck.ComponentName;
+import org.apache.james.core.healthcheck.HealthCheck;
+import org.apache.james.core.healthcheck.Result;
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.client.Requests;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+
+
+public class ElasticSearchHealthCheck implements HealthCheck {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticSearchHealthCheck.class);
+    private static final ComponentName COMPONENT_NAME = new ComponentName("ElasticSearch Backend");
+
+    private final Set<IndexName> indexNames;
+    private final RestHighLevelClient client;
+
+    @Inject
+    ElasticSearchHealthCheck(RestHighLevelClient client, Set<IndexName> indexNames) {
+        this.client = client;
+        this.indexNames = indexNames;
+    }
+
+    @Override
+    public ComponentName componentName() {
+        return COMPONENT_NAME;
+    }
+
+    @Override
+    public Result check() {
+        String[] indices = indexNames.stream()
+            .map(IndexName::getValue)
+            .toArray(String[]::new);
+        ClusterHealthRequest request = Requests.clusterHealthRequest(indices);
+
+        try {
+            ClusterHealthResponse response = client.cluster()
+                .health(request, RequestOptions.DEFAULT);
+
+            return toHealthCheckResult(response);
+        } catch (IOException e) {
+            LOGGER.error("Error while contacting cluster", e);
+            return Result.unhealthy(COMPONENT_NAME, "Error while contacting cluster. Check James server logs.");
+        }
+    }
+
+    @VisibleForTesting
+    Result toHealthCheckResult(ClusterHealthResponse response) {
+        switch (response.getStatus()) {
+            case GREEN:
+            case YELLOW:
+                return Result.healthy(COMPONENT_NAME);
+            case RED:
+                return Result.unhealthy(COMPONENT_NAME, response.getClusterName() + " status is RED");
+            default:
+                throw new NotImplementedException("Un-handled ElasticSearch cluster status");
+        }
+    }
+}
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java
index 9398dae..e3365b2 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/DockerElasticSearch.java
@@ -114,12 +114,23 @@ public class DockerElasticSearch {
         }
     }
 
+    public ElasticSearchConfiguration configuration(Optional<Duration> requestTimeout) {
+        return ElasticSearchConfiguration.builder()
+            .addHost(getHttpHost())
+            .requestTimeout(requestTimeout)
+            .build();
+    }
+
     public ElasticSearchConfiguration configuration() {
-        return ElasticSearchConfiguration.builder().addHost(getHttpHost()).build();
+        return configuration(Optional.empty());
     }
 
     public ClientProvider clientProvider() {
-        return new ClientProvider(configuration());
+        return new ClientProvider(configuration(Optional.empty()));
+    }
+
+    public ClientProvider clientProvider(Duration requestTimeout) {
+        return new ClientProvider(configuration(Optional.of(requestTimeout)));
     }
 
     private ElasticSearchAPI esAPI() {
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchClientModule.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchHealthCheckConnectionTest.java
similarity index 50%
copy from server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchClientModule.java
copy to backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchHealthCheckConnectionTest.java
index d6a6c11..448390f 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchClientModule.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchHealthCheckConnectionTest.java
@@ -16,21 +16,47 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
+package org.apache.james.backends.es;
 
-package org.apache.james.modules.mailbox;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.time.Duration;
 
-import org.apache.james.backends.es.ClientProvider;
 import org.elasticsearch.client.RestHighLevelClient;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+public class ElasticSearchHealthCheckConnectionTest {
+    private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(5);
+
+    @Rule
+    public DockerElasticSearchRule elasticSearch = new DockerElasticSearchRule();
+    private ElasticSearchHealthCheck elasticSearchHealthCheck;
 
-import com.google.inject.AbstractModule;
-import com.google.inject.Scopes;
+    @Before
+    public void setUp() {
+        RestHighLevelClient client = elasticSearch.getDockerElasticSearch().clientProvider(REQUEST_TIMEOUT).get();
 
-public class ElasticSearchClientModule extends AbstractModule {
+        elasticSearchHealthCheck = new ElasticSearchHealthCheck(client, ImmutableSet.of());
+    }
 
-    @Override
-    protected void configure() {
-        bind(ClientProvider.class).in(Scopes.SINGLETON);
-        bind(RestHighLevelClient.class).toProvider(ClientProvider.class);
+    @Test
+    public void checkShouldSucceedWhenElasticSearchIsRunning() {
+        assertThat(elasticSearchHealthCheck.check().isHealthy()).isTrue();
     }
 
+    @Test
+    public void checkShouldFailWhenElasticSearchIsPaused() {
+
+        elasticSearch.getDockerElasticSearch().pause();
+
+        try {
+            assertThat(elasticSearchHealthCheck.check().isUnHealthy()).isTrue();
+        } finally {
+            elasticSearch.getDockerElasticSearch().unpause();
+        }
+    }
 }
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchHealthCheckTest.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchHealthCheckTest.java
new file mode 100644
index 0000000..feef5da
--- /dev/null
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchHealthCheckTest.java
@@ -0,0 +1,79 @@
+/****************************************************************
+ * 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.backends.es;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
+import org.elasticsearch.cluster.ClusterName;
+import org.elasticsearch.cluster.ClusterState;
+import org.elasticsearch.cluster.block.ClusterBlocks;
+import org.elasticsearch.cluster.health.ClusterHealthStatus;
+import org.elasticsearch.cluster.node.DiscoveryNodes;
+import org.elasticsearch.cluster.routing.RoutingTable;
+import org.junit.Before;
+import org.junit.Test;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableSet;
+
+public class ElasticSearchHealthCheckTest {
+    private ElasticSearchHealthCheck healthCheck;
+
+    @Before
+    public void setup() {
+        healthCheck = new ElasticSearchHealthCheck(null, ImmutableSet.of());
+    }
+
+    @Test
+    public void checkShouldReturnHealthyWhenElasticSearchClusterHealthStatusIsGreen() {
+        FakeClusterHealthResponse response = new FakeClusterHealthResponse(ClusterHealthStatus.GREEN);
+
+        assertThat(healthCheck.toHealthCheckResult(response).isHealthy()).isTrue();
+    }
+
+    @Test
+    public void checkShouldReturnUnHealthyWhenElasticSearchClusterHealthStatusIsRed() {
+        FakeClusterHealthResponse response = new FakeClusterHealthResponse(ClusterHealthStatus.RED);
+
+        assertThat(healthCheck.toHealthCheckResult(response).isUnHealthy()).isTrue();
+    }
+
+    @Test
+    public void checkShouldReturnHealthyWhenElasticSearchClusterHealthStatusIsYellow() {
+        FakeClusterHealthResponse response = new FakeClusterHealthResponse(ClusterHealthStatus.YELLOW);
+
+        assertThat(healthCheck.toHealthCheckResult(response).isHealthy()).isTrue();
+    }
+
+    private static class FakeClusterHealthResponse extends ClusterHealthResponse {
+        private final ClusterHealthStatus status;
+
+        private FakeClusterHealthResponse(ClusterHealthStatus clusterHealthStatus) {
+            super("fake-cluster", new String[0],
+                new ClusterState(new ClusterName("fake-cluster"), 0, null, null, RoutingTable.builder().build(),
+                    DiscoveryNodes.builder().build(),
+                    ClusterBlocks.builder().build(), null, false));
+            this.status = clusterHealthStatus;
+        }
+
+        @Override
+        public ClusterHealthStatus getStatus() {
+            return this.status;
+        }
+    }
+}
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchClientModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchClientModule.java
index d6a6c11..7aab691 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchClientModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchClientModule.java
@@ -19,11 +19,22 @@
 
 package org.apache.james.modules.mailbox;
 
+import java.util.Set;
+
 import org.apache.james.backends.es.ClientProvider;
+import org.apache.james.backends.es.ElasticSearchHealthCheck;
+import org.apache.james.backends.es.IndexName;
+import org.apache.james.core.healthcheck.HealthCheck;
+import org.apache.james.mailbox.elasticsearch.ElasticSearchMailboxConfiguration;
+import org.apache.james.quota.search.elasticsearch.ElasticSearchQuotaConfiguration;
 import org.elasticsearch.client.RestHighLevelClient;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
 import com.google.inject.Scopes;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
 
 public class ElasticSearchClientModule extends AbstractModule {
 
@@ -31,6 +42,18 @@ public class ElasticSearchClientModule extends AbstractModule {
     protected void configure() {
         bind(ClientProvider.class).in(Scopes.SINGLETON);
         bind(RestHighLevelClient.class).toProvider(ClientProvider.class);
+
+        Multibinder.newSetBinder(binder(), HealthCheck.class)
+            .addBinding()
+            .to(ElasticSearchHealthCheck.class);
     }
 
+    @Provides
+    @Singleton
+    Set<IndexName> provideIndexNames(ElasticSearchMailboxConfiguration mailboxConfiguration,
+                                     ElasticSearchQuotaConfiguration quotaConfiguration) {
+        return ImmutableSet.of(
+            mailboxConfiguration.getIndexMailboxName(),
+            quotaConfiguration.getIndexQuotaRatioName());
+    }
 }


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