james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From btell...@apache.org
Subject [07/15] james-project git commit: JAMES-2202 Handle a read and a write alias
Date Wed, 01 Nov 2017 11:00:05 GMT
JAMES-2202 Handle a read and a write alias

Code was bloating due to index and alias creation. I thus decided to:
 - Separate concerns of configuration parsing and injection
 - Make IndexCreationFatory a real factory


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/f3b6ac5d
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/f3b6ac5d
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/f3b6ac5d

Branch: refs/heads/master
Commit: f3b6ac5db1f8fbbea401381a47651b9b0f1227cc
Parents: e3e00e1
Author: benwa <btellier@linagora.com>
Authored: Wed Oct 25 13:40:35 2017 +0700
Committer: benwa <btellier@linagora.com>
Committed: Wed Nov 1 17:54:21 2017 +0700

----------------------------------------------------------------------
 .../james/backends/es/ClientProviderImpl.java   |   5 +
 .../backends/es/DeleteByQueryPerformer.java     |   2 +-
 .../backends/es/ElasticSearchConstants.java     |  25 ++
 .../james/backends/es/ElasticSearchIndexer.java |   5 +-
 .../james/backends/es/IndexCreationFactory.java |  65 +++-
 .../backends/es/ElasticSearchIndexerTest.java   |   6 +-
 .../backends/es/IndexCreationFactoryTest.java   |  10 +-
 .../backends/es/NodeMappingFactoryTest.java     |   5 +-
 .../backends/es/search/ScrollIterableTest.java  |   5 +-
 .../MailboxElasticsearchConstants.java          |   3 +-
 .../search/ElasticSearchSearcher.java           |   4 +-
 .../ElasticSearchIntegrationTest.java           |  15 +-
 .../host/ElasticSearchHostSystem.java           |  15 +-
 .../mailbox/ElasticSearchConfiguration.java     | 185 +++++++++-
 .../mailbox/ElasticSearchMailboxModule.java     | 141 +++-----
 .../apache/james/DockerElasticSearchRule.java   |  14 +-
 .../james/modules/TestElasticSearchModule.java  |   9 +-
 .../mailbox/ElasticSearchConfigurationTest.java | 347 +++++++++++++++++++
 .../mailbox/ElasticSearchMailboxModuleTest.java | 215 ------------
 .../main/java/org/apache/james/util/Host.java   |   3 +-
 src/site/xdoc/server/config-elasticsearch.xml   |   9 +-
 21 files changed, 723 insertions(+), 365 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ClientProviderImpl.java
----------------------------------------------------------------------
diff --git a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ClientProviderImpl.java b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ClientProviderImpl.java
index a56e056..6118739 100644
--- a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ClientProviderImpl.java
+++ b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ClientProviderImpl.java
@@ -42,6 +42,11 @@ public class ClientProviderImpl implements ClientProvider {
         return new ClientProviderImpl(Host.parseHosts(hostsString));
     }
 
+    public static ClientProviderImpl fromHosts(ImmutableList<Host> hosts) {
+        Preconditions.checkNotNull(hosts, "Hosts should not be null");
+        return new ClientProviderImpl(hosts);
+    }
+
     private static boolean isValidPort(Integer port) {
         return port > 0 && port <= 65535;
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/DeleteByQueryPerformer.java
----------------------------------------------------------------------
diff --git a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/DeleteByQueryPerformer.java b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/DeleteByQueryPerformer.java
index 0ccea46..6c8c2e3 100644
--- a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/DeleteByQueryPerformer.java
+++ b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/DeleteByQueryPerformer.java
@@ -47,7 +47,7 @@ public class DeleteByQueryPerformer {
     private final TypeName typeName;
 
     @Inject
-    public DeleteByQueryPerformer(Client client, @Named("AsyncExecutor") ExecutorService executor, AliasName aliasName, TypeName typeName) {
+    public DeleteByQueryPerformer(Client client, @Named("AsyncExecutor") ExecutorService executor, @Named(ElasticSearchConstants.WRITE_ALIAS) AliasName aliasName, TypeName typeName) {
         this(client, executor, DEFAULT_BATCH_SIZE, aliasName, typeName);
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchConstants.java
----------------------------------------------------------------------
diff --git a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchConstants.java b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchConstants.java
new file mode 100644
index 0000000..8830208
--- /dev/null
+++ b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchConstants.java
@@ -0,0 +1,25 @@
+/****************************************************************
+ * 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;
+
+public interface ElasticSearchConstants {
+    String WRITE_ALIAS = "injectWriteAlias";
+    String READ_ALIAS = "injectReadAlias";
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/ElasticSearchIndexer.java
----------------------------------------------------------------------
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 d162a0c..57dbc9e 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
@@ -23,6 +23,7 @@ import java.util.Objects;
 import java.util.Optional;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.apache.commons.lang3.StringUtils;
 import org.elasticsearch.action.bulk.BulkRequestBuilder;
@@ -92,7 +93,9 @@ public class ElasticSearchIndexer {
     private final TypeName typeName;
 
     @Inject
-    public ElasticSearchIndexer(Client client, DeleteByQueryPerformer deleteByQueryPerformer, AliasName aliasName, TypeName typeName) {
+    public ElasticSearchIndexer(Client client, DeleteByQueryPerformer deleteByQueryPerformer,
+                                @Named(ElasticSearchConstants.WRITE_ALIAS) AliasName aliasName,
+                                TypeName typeName) {
         this.client = client;
         this.deleteByQueryPerformer = deleteByQueryPerformer;
         this.aliasName = aliasName;

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/IndexCreationFactory.java
----------------------------------------------------------------------
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 2eb9e1b..a4bcc84 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
@@ -22,6 +22,7 @@ package org.apache.james.backends.es;
 import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
 
 import java.io.IOException;
+import java.util.Optional;
 
 import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
 import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
@@ -31,6 +32,9 @@ import org.elasticsearch.indices.IndexAlreadyExistsException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
 public class IndexCreationFactory {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(IndexCreationFactory.class);
@@ -38,26 +42,55 @@ public class IndexCreationFactory {
     private static final int DEFAULT_NB_REPLICA = 0;
     public static final String CASE_INSENSITIVE = "case_insensitive";
 
-    public static Client createIndexAndAlias(Client client, IndexName indexName, AliasName aliasName, int nbShards, int nbReplica) {
-        try {
-            return createIndexAndAlias(client, indexName, aliasName, generateSetting(nbShards, nbReplica));
-        } catch (IOException e) {
-            LOGGER.error("Error while creating index : ", e);
-            return client;
-        }
+    private IndexName indexName;
+    private ImmutableList.Builder<AliasName> aliases;
+    private Optional<Integer> nbShards;
+    private Optional<Integer> nbReplica;
+
+    public IndexCreationFactory() {
+        indexName = null;
+        aliases = ImmutableList.builder();
+        nbShards = Optional.empty();
+        nbReplica = Optional.empty();
+    }
+
+    public IndexCreationFactory onIndex(IndexName indexName) {
+        Preconditions.checkNotNull(indexName);
+        this.indexName = indexName;
+        return this;
     }
 
-    public static Client createIndexAndAlias(Client client, IndexName indexName, AliasName aliasName) {
-        return createIndexAndAlias(client, indexName, aliasName, DEFAULT_NB_SHARDS, DEFAULT_NB_REPLICA);
+    public IndexCreationFactory addAlias(AliasName aliasName) {
+        Preconditions.checkNotNull(aliasName);
+        this.aliases.add(aliasName);
+        return this;
     }
 
-    private static Client createIndexAndAlias(Client client, IndexName indexName, AliasName aliasName, XContentBuilder settings) {
-        createIndexIfNeeded(client, indexName, settings);
-        createAliasIfNeeded(client, indexName, aliasName);
+    public IndexCreationFactory nbShards(int nbShards) {
+        this.nbShards = Optional.of(nbShards);
+        return this;
+    }
+
+    public IndexCreationFactory nbReplica(int nbReplica) {
+        this.nbReplica = Optional.of(nbReplica);
+        return this;
+    }
+
+    public Client createIndexAndAliases(Client client) {
+        Preconditions.checkNotNull(indexName);
+        try {
+            createIndexIfNeeded(client, indexName, generateSetting(
+                nbShards.orElse(DEFAULT_NB_SHARDS),
+                nbReplica.orElse(DEFAULT_NB_REPLICA)));
+            aliases.build()
+                .forEach(alias -> createAliasIfNeeded(client, indexName, alias));
+        } catch (IOException e) {
+            LOGGER.error("Error while creating index : ", e);
+        }
         return client;
     }
 
-    private static void createAliasIfNeeded(Client client, IndexName indexName, AliasName aliasName) {
+    private void createAliasIfNeeded(Client client, IndexName indexName, AliasName aliasName) {
         if (!aliasExist(client, aliasName)) {
             client.admin()
                 .indices()
@@ -67,7 +100,7 @@ public class IndexCreationFactory {
         }
     }
 
-    private static boolean aliasExist(Client client, AliasName aliasName) {
+    private boolean aliasExist(Client client, AliasName aliasName) {
         return client.admin()
             .indices()
             .aliasesExist(new GetAliasesRequest()
@@ -76,7 +109,7 @@ public class IndexCreationFactory {
             .exists();
     }
 
-    private static void createIndexIfNeeded(Client client, IndexName indexName, XContentBuilder settings) {
+    private void createIndexIfNeeded(Client client, IndexName indexName, XContentBuilder settings) {
         try {
             client.admin()
                 .indices()
@@ -89,7 +122,7 @@ public class IndexCreationFactory {
         }
     }
 
-    private static XContentBuilder generateSetting(int nbShards, int nbReplica) throws IOException {
+    private XContentBuilder generateSetting(int nbShards, int nbReplica) throws IOException {
         return jsonBuilder()
             .startObject()
                 .field("number_of_shards", nbShards)

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/ElasticSearchIndexerTest.java
----------------------------------------------------------------------
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 a4f9aca..a3a6d9c 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
@@ -58,8 +58,10 @@ public class ElasticSearchIndexerTest {
     public void setup() throws IOException {
         node = embeddedElasticSearch.getNode();
         TestingClientProvider clientProvider = new TestingClientProvider(node);
-        IndexCreationFactory.createIndexAndAlias(clientProvider.get(),
-            INDEX_NAME, ALIAS_NAME);
+        new IndexCreationFactory()
+            .onIndex(INDEX_NAME)
+            .addAlias(ALIAS_NAME)
+            .createIndexAndAliases(clientProvider.get());
         DeleteByQueryPerformer deleteByQueryPerformer = new DeleteByQueryPerformer(clientProvider.get(),
             Executors.newSingleThreadExecutor(),
             MINIMUM_BATCH_SIZE,

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/IndexCreationFactoryTest.java
----------------------------------------------------------------------
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/IndexCreationFactoryTest.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/IndexCreationFactoryTest.java
index dee1142..7735eb9 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/IndexCreationFactoryTest.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/IndexCreationFactoryTest.java
@@ -41,11 +41,17 @@ public class IndexCreationFactoryTest {
     @Before
     public void setUp() {
         clientProvider = new TestingClientProvider(embeddedElasticSearch.getNode());
-        IndexCreationFactory.createIndexAndAlias(clientProvider.get(), INDEX_NAME, ALIAS_NAME);
+        new IndexCreationFactory()
+            .onIndex(INDEX_NAME)
+            .addAlias(ALIAS_NAME)
+            .createIndexAndAliases(clientProvider.get());
     }
 
     @Test
     public void createIndexAndAliasShouldNotThrowWhenCalledSeveralTime() {
-        IndexCreationFactory.createIndexAndAlias(clientProvider.get(), INDEX_NAME, ALIAS_NAME);
+        new IndexCreationFactory()
+            .onIndex(INDEX_NAME)
+            .addAlias(ALIAS_NAME)
+            .createIndexAndAliases(clientProvider.get());
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/NodeMappingFactoryTest.java
----------------------------------------------------------------------
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/NodeMappingFactoryTest.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/NodeMappingFactoryTest.java
index 6aca8d7..1e0eb79 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/NodeMappingFactoryTest.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/NodeMappingFactoryTest.java
@@ -46,7 +46,10 @@ public class NodeMappingFactoryTest {
     @Before
     public void setUp() throws Exception {
         clientProvider = new TestingClientProvider(embeddedElasticSearch.getNode());
-        IndexCreationFactory.createIndexAndAlias(clientProvider.get(), INDEX_NAME, ALIAS_NAME);
+        new IndexCreationFactory()
+            .onIndex(INDEX_NAME)
+            .addAlias(ALIAS_NAME)
+            .createIndexAndAliases(clientProvider.get());
         NodeMappingFactory.applyMapping(clientProvider.get(),
             INDEX_NAME,
             TYPE_NAME,

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/search/ScrollIterableTest.java
----------------------------------------------------------------------
diff --git a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/search/ScrollIterableTest.java b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/search/ScrollIterableTest.java
index 4515f96..b296b8e 100644
--- a/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/search/ScrollIterableTest.java
+++ b/backends-common/elasticsearch/src/test/java/org/apache/james/backends/es/search/ScrollIterableTest.java
@@ -67,7 +67,10 @@ public class ScrollIterableTest {
     @Before
     public void setUp() throws Exception {
         clientProvider = new TestingClientProvider(embeddedElasticSearch.getNode());
-        IndexCreationFactory.createIndexAndAlias(clientProvider.get(), INDEX_NAME, ALIAS_NAME);
+        new IndexCreationFactory()
+            .onIndex(INDEX_NAME)
+            .addAlias(ALIAS_NAME)
+            .createIndexAndAliases(clientProvider.get());
         embeddedElasticSearch.awaitForElasticSearch();
         NodeMappingFactory.applyMapping(clientProvider.get(), INDEX_NAME, TYPE_NAME, getMappingsSources());
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/MailboxElasticsearchConstants.java
----------------------------------------------------------------------
diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/MailboxElasticsearchConstants.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/MailboxElasticsearchConstants.java
index fb89b8e..e1d87c2 100644
--- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/MailboxElasticsearchConstants.java
+++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/MailboxElasticsearchConstants.java
@@ -24,7 +24,8 @@ import org.apache.james.backends.es.IndexName;
 import org.apache.james.backends.es.TypeName;
 
 public interface MailboxElasticsearchConstants {
-    AliasName DEFAULT_MAILBOX_ALIAS = new AliasName("mailboxAlias");
+    AliasName DEFAULT_MAILBOX_WRITE_ALIAS = new AliasName("mailboxWriteAlias");
+    AliasName DEFAULT_MAILBOX_READ_ALIAS = new AliasName("mailboxReadAlias");
     IndexName DEFAULT_MAILBOX_INDEX = new IndexName("mailbox");
     TypeName MESSAGE_TYPE = new TypeName("message");
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcher.java
----------------------------------------------------------------------
diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcher.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcher.java
index cc330e8..acf7baf 100644
--- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcher.java
+++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/search/ElasticSearchSearcher.java
@@ -24,7 +24,9 @@ import java.util.Optional;
 import java.util.stream.Stream;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
+import org.apache.james.backends.es.ElasticSearchConstants;
 import org.apache.james.backends.es.AliasName;
 import org.apache.james.backends.es.TypeName;
 import org.apache.james.backends.es.search.ScrollIterable;
@@ -64,7 +66,7 @@ public class ElasticSearchSearcher {
     @Inject
     public ElasticSearchSearcher(Client client, QueryConverter queryConverter,
                                  MailboxId.Factory mailboxIdFactory, MessageId.Factory messageIdFactory,
-                                 AliasName aliasName, TypeName typeName) {
+                                 @Named(ElasticSearchConstants.READ_ALIAS) AliasName aliasName, TypeName typeName) {
         this(client, queryConverter, DEFAULT_SIZE, mailboxIdFactory, messageIdFactory, aliasName, typeName);
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
----------------------------------------------------------------------
diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
index f32f895..4e18134 100644
--- a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
+++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/ElasticSearchIntegrationTest.java
@@ -110,10 +110,11 @@ public class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest
     @Override
     protected void initializeMailboxManager() throws Exception {
         Client client = NodeMappingFactory.applyMapping(
-            IndexCreationFactory.createIndexAndAlias(
-                new TestingClientProvider(embeddedElasticSearch.getNode()).get(),
-                MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX,
-                MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS),
+            new IndexCreationFactory()
+                .onIndex(MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX)
+                .addAlias( MailboxElasticsearchConstants.DEFAULT_MAILBOX_READ_ALIAS)
+                .addAlias( MailboxElasticsearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS)
+                .createIndexAndAliases(new TestingClientProvider(embeddedElasticSearch.getNode()).get()),
             MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX,
             MailboxElasticsearchConstants.MESSAGE_TYPE,
             MailboxMappingFactory.getMappingContent());
@@ -126,13 +127,13 @@ public class ElasticSearchIntegrationTest extends AbstractMessageSearchIndexTest
                 new DeleteByQueryPerformer(client,
                     Executors.newSingleThreadExecutor(),
                     BATCH_SIZE,
-                    MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS,
+                    MailboxElasticsearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS,
                     MailboxElasticsearchConstants.MESSAGE_TYPE),
-                MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS,
+                MailboxElasticsearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS,
                 MailboxElasticsearchConstants.MESSAGE_TYPE),
             new ElasticSearchSearcher(client, new QueryConverter(new CriterionConverter()), SEARCH_SIZE,
                 new InMemoryId.Factory(), messageIdFactory,
-                MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS,
+                MailboxElasticsearchConstants.DEFAULT_MAILBOX_READ_ALIAS,
                 MailboxElasticsearchConstants.MESSAGE_TYPE),
             new MessageToElasticSearchJson(textExtractor, ZoneId.of("Europe/Paris"), IndexAttachments.YES));
         storeMailboxManager = new InMemoryMailboxManager(

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/mpt/impl/imap-mailbox/elasticsearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/ElasticSearchHostSystem.java
----------------------------------------------------------------------
diff --git a/mpt/impl/imap-mailbox/elasticsearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/ElasticSearchHostSystem.java b/mpt/impl/imap-mailbox/elasticsearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/ElasticSearchHostSystem.java
index cc6b435..d83f96f 100644
--- a/mpt/impl/imap-mailbox/elasticsearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/ElasticSearchHostSystem.java
+++ b/mpt/impl/imap-mailbox/elasticsearch/src/test/java/org/apache/james/mpt/imapmailbox/elasticsearch/host/ElasticSearchHostSystem.java
@@ -95,10 +95,11 @@ public class ElasticSearchHostSystem extends JamesImapHostSystem {
 
     private void initFields() {
         Client client = NodeMappingFactory.applyMapping(
-            IndexCreationFactory.createIndexAndAlias(
-                new TestingClientProvider(embeddedElasticSearch.getNode()).get(),
-                MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX,
-                MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS),
+            new IndexCreationFactory()
+                .onIndex(MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX)
+                .addAlias(MailboxElasticsearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS)
+                .addAlias(MailboxElasticsearchConstants.DEFAULT_MAILBOX_READ_ALIAS)
+                .createIndexAndAliases(new TestingClientProvider(embeddedElasticSearch.getNode()).get()),
             MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX,
             MailboxElasticsearchConstants.MESSAGE_TYPE,
             MailboxMappingFactory.getMappingContent());
@@ -109,12 +110,12 @@ public class ElasticSearchHostSystem extends JamesImapHostSystem {
         ElasticSearchListeningMessageSearchIndex searchIndex = new ElasticSearchListeningMessageSearchIndex(
             factory,
             new ElasticSearchIndexer(client,
-                new DeleteByQueryPerformer(client, Executors.newSingleThreadExecutor(), MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS, MailboxElasticsearchConstants.MESSAGE_TYPE),
-                MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS,
+                new DeleteByQueryPerformer(client, Executors.newSingleThreadExecutor(), MailboxElasticsearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS, MailboxElasticsearchConstants.MESSAGE_TYPE),
+                MailboxElasticsearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS,
                 MailboxElasticsearchConstants.MESSAGE_TYPE),
             new ElasticSearchSearcher(client,
                 new QueryConverter(new CriterionConverter()), new InMemoryId.Factory(), messageIdFactory,
-                MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS, MailboxElasticsearchConstants.MESSAGE_TYPE),
+                MailboxElasticsearchConstants.DEFAULT_MAILBOX_READ_ALIAS, MailboxElasticsearchConstants.MESSAGE_TYPE),
             new MessageToElasticSearchJson(new DefaultTextExtractor(), ZoneId.systemDefault(), IndexAttachments.YES));
 
         MailboxACLResolver aclResolver = new UnionMailboxACLResolver();

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
index 0c39e81..7d65618 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
@@ -19,13 +19,192 @@
 
 package org.apache.james.modules.mailbox;
 
+import java.util.Objects;
+import java.util.Optional;
+
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.james.backends.es.AliasName;
+import org.apache.james.backends.es.IndexName;
+import org.apache.james.mailbox.elasticsearch.IndexAttachments;
+import org.apache.james.mailbox.elasticsearch.MailboxElasticsearchConstants;
+import org.apache.james.util.Host;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+
+public class ElasticSearchConfiguration {
+    public static final String ELASTICSEARCH_HOSTS = "elasticsearch.hosts";
+    public static final String ELASTICSEARCH_MASTER_HOST = "elasticsearch.masterHost";
+    public static final String ELASTICSEARCH_PORT = "elasticsearch.port";
+    public static final String ELASTICSEARCH_INDEX_NAME = "elasticsearch.index.name";
+    public static final String ELASTICSEARCH_NB_REPLICA = "elasticsearch.nb.replica";
+    public static final String ELASTICSEARCH_NB_SHARDS = "elasticsearch.nb.shards";
+    public static final String ELASTICSEARCH_ALIAS_READ_NAME = "elasticsearch.alias.read.name";
+    public static final String ELASTICSEARCH_ALIAS_WRITE_NAME = "elasticsearch.alias.write.name";
+    public static final String ELASTICSEARCH_RETRY_CONNECTION_MIN_DELAY = "elasticsearch.retryConnection.minDelay";
+    public static final String ELASTICSEARCH_RETRY_CONNECTION_MAX_RETRIES = "elasticsearch.retryConnection.maxRetries";
+    public static final String ELASTICSEARCH_INDEX_ATTACHMENTS = "elasticsearch.indexAttachments";
+
+    public static final int DEFAULT_CONNECTION_MAX_RETRIES = 7;
+    public static final int DEFAULT_CONNECTION_MIN_DELAY = 3000;
+    public static final boolean DEFAULT_INDEX_ATTACHMENTS = true;
+    public static final int DEFAULT_NB_SHARDS = 1;
+    public static final int DEFAULT_NB_REPLICA = 0;
+    public static final int DEFAULT_PORT = 9300;
+
+    public static ElasticSearchConfiguration fromProperties(PropertiesConfiguration configuration) throws ConfigurationException {
+        int nbShards = configuration.getInt(ELASTICSEARCH_NB_SHARDS, DEFAULT_NB_SHARDS);
+        int nbReplica = configuration.getInt(ELASTICSEARCH_NB_REPLICA, DEFAULT_NB_REPLICA);
+        int maxRetries = configuration.getInt(ELASTICSEARCH_RETRY_CONNECTION_MAX_RETRIES, DEFAULT_CONNECTION_MAX_RETRIES);
+        int minDelay = configuration.getInt(ELASTICSEARCH_RETRY_CONNECTION_MIN_DELAY, DEFAULT_CONNECTION_MIN_DELAY);
+        IndexAttachments indexAttachments = provideIndexAttachments(configuration);
+        ImmutableList<Host> hosts = getHosts(configuration);
+
+        AliasName readAlias = Optional.ofNullable(configuration.getString(ELASTICSEARCH_ALIAS_READ_NAME))
+            .map(AliasName::new)
+            .orElse(MailboxElasticsearchConstants.DEFAULT_MAILBOX_READ_ALIAS);
+        AliasName writeAlias = Optional.ofNullable(configuration.getString(ELASTICSEARCH_ALIAS_WRITE_NAME))
+            .map(AliasName::new)
+            .orElse(MailboxElasticsearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS);
+        IndexName indexName = Optional.ofNullable(configuration.getString(ELASTICSEARCH_INDEX_NAME))
+            .map(IndexName::new)
+            .orElse(MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX);
+
+        return new ElasticSearchConfiguration(
+            hosts,
+            indexName,
+            readAlias,
+            writeAlias,
+            nbShards,
+            nbReplica,
+            minDelay,
+            maxRetries,
+            indexAttachments);
+    }
+
+    private static IndexAttachments provideIndexAttachments(PropertiesConfiguration configuration) {
+        if (configuration.getBoolean(ELASTICSEARCH_INDEX_ATTACHMENTS, DEFAULT_INDEX_ATTACHMENTS)) {
+            return IndexAttachments.YES;
+        }
+        return IndexAttachments.NO;
+    }
+
+    private static ImmutableList<Host> getHosts(PropertiesConfiguration propertiesReader) throws ConfigurationException {
+        Optional<String> monoHostAddress = Optional.ofNullable(
+            propertiesReader.getString(ELASTICSEARCH_MASTER_HOST, null));
+        Optional<Integer> monoHostPort = Optional.ofNullable(
+            propertiesReader.getInteger(ELASTICSEARCH_PORT, null));
+        Optional<String> multiHosts = Optional.ofNullable(
+            propertiesReader.getString(ELASTICSEARCH_HOSTS, null));
+
+        validateHostsConfigurationOptions(monoHostAddress, monoHostPort, multiHosts);
+
+        if (monoHostAddress.isPresent()) {
+            return ImmutableList.of(
+                Host.from(monoHostAddress.get(),
+                monoHostPort.get()));
+        } else {
+            return Host.parseHosts(multiHosts.get(), DEFAULT_PORT);
+        }
+    }
+
+    @VisibleForTesting
+    static void validateHostsConfigurationOptions(Optional<String> monoHostAddress,
+                                                  Optional<Integer> monoHostPort,
+                                                  Optional<String> multiHosts) throws ConfigurationException {
+        if (monoHostAddress.isPresent() != monoHostPort.isPresent()) {
+            throw new ConfigurationException(ELASTICSEARCH_MASTER_HOST + " and " + ELASTICSEARCH_PORT + " should be specified together");
+        }
+        if (multiHosts.isPresent() && monoHostAddress.isPresent()) {
+            throw new ConfigurationException("You should choose between mono host set up and " + ELASTICSEARCH_HOSTS);
+        }
+        if (!multiHosts.isPresent() && !monoHostAddress.isPresent()) {
+            throw new ConfigurationException("You should specify either (" + ELASTICSEARCH_MASTER_HOST + " and " + ELASTICSEARCH_PORT + ") or " + ELASTICSEARCH_HOSTS);
+        }
+    }
+
+    private final ImmutableList<Host> hosts;
+    private final IndexName indexName;
+    private final AliasName readAliasName;
+    private final AliasName writeAliasName;
+    private final int nbShards;
+    private final int nbReplica;
+    private final int minDelay;
+    private final int maxRetries;
+    private final IndexAttachments indexAttachment;
+
+    public ElasticSearchConfiguration(ImmutableList<Host> hosts, IndexName indexName, AliasName readAliasName,
+                                      AliasName writeAliasName, int nbShards, int nbReplica, int minDelay,
+                                      int maxRetries, IndexAttachments indexAttachment) {
+        this.hosts = hosts;
+        this.indexName = indexName;
+        this.readAliasName = readAliasName;
+        this.writeAliasName = writeAliasName;
+        this.nbShards = nbShards;
+        this.nbReplica = nbReplica;
+        this.minDelay = minDelay;
+        this.maxRetries = maxRetries;
+        this.indexAttachment = indexAttachment;
+    }
+
+    public ImmutableList<Host> getHosts() {
+        return hosts;
+    }
+
+    public IndexName getIndexName() {
+        return indexName;
+    }
+
+    public AliasName getReadAliasName() {
+        return readAliasName;
+    }
+
+    public AliasName getWriteAliasName() {
+        return writeAliasName;
+    }
+
+    public int getNbShards() {
+        return nbShards;
+    }
+
+    public int getNbReplica() {
+        return nbReplica;
+    }
+
+    public int getMinDelay() {
+        return minDelay;
+    }
+
+    public int getMaxRetries() {
+        return maxRetries;
+    }
 
-import java.io.FileNotFoundException;
+    public IndexAttachments getIndexAttachment() {
+        return indexAttachment;
+    }
 
-public interface ElasticSearchConfiguration {
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof ElasticSearchConfiguration) {
+            ElasticSearchConfiguration that = (ElasticSearchConfiguration) o;
 
-    PropertiesConfiguration getConfiguration() throws FileNotFoundException, ConfigurationException;
+            return Objects.equals(this.nbShards, that.nbShards)
+                && Objects.equals(this.nbReplica, that.nbReplica)
+                && Objects.equals(this.minDelay, that.minDelay)
+                && Objects.equals(this.maxRetries, that.maxRetries)
+                && Objects.equals(this.indexAttachment, that.indexAttachment)
+                && Objects.equals(this.hosts, that.hosts)
+                && Objects.equals(this.indexName, that.indexName)
+                && Objects.equals(this.readAliasName, that.readAliasName)
+                && Objects.equals(this.writeAliasName, that.writeAliasName);
+        }
+        return false;
+    }
 
+    @Override
+    public final int hashCode() {
+        return Objects.hash(hosts, indexName, readAliasName, writeAliasName, nbShards,
+            nbReplica, minDelay, maxRetries, indexAttachment);
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
index ea59317..d9e7858 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
@@ -21,13 +21,14 @@ package org.apache.james.modules.mailbox;
 
 import java.io.FileNotFoundException;
 import java.time.LocalDateTime;
-import java.util.Optional;
 import java.util.concurrent.ExecutionException;
 
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.james.backends.es.ElasticSearchConstants;
 import org.apache.james.backends.es.AliasName;
 import org.apache.james.backends.es.ClientProviderImpl;
 import org.apache.james.backends.es.IndexCreationFactory;
@@ -47,7 +48,6 @@ import org.elasticsearch.client.transport.NoNodeAvailableException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.annotations.VisibleForTesting;
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 import com.google.inject.Scopes;
@@ -57,14 +57,6 @@ public class ElasticSearchMailboxModule extends AbstractModule {
     private static final Logger LOGGER = LoggerFactory.getLogger(ElasticSearchMailboxModule.class);
 
     public static final String ELASTICSEARCH_CONFIGURATION_NAME = "elasticsearch";
-    public static final String ELASTICSEARCH_HOSTS = "elasticsearch.hosts";
-    public static final String ELASTICSEARCH_MASTER_HOST = "elasticsearch.masterHost";
-    public static final String ELASTICSEARCH_PORT = "elasticsearch.port";
-    private static final int DEFAULT_CONNECTION_MAX_RETRIES = 7;
-    private static final int DEFAULT_CONNECTION_MIN_DELAY = 3000;
-    private static final boolean DEFAULT_INDEX_ATTACHMENTS = true;
-    private static final int DEFAULT_NB_SHARDS = 1;
-    private static final int DEFAULT_NB_REPLICA = 0;
     private static final String LOCALHOST = "127.0.0.1";
 
     @Override
@@ -76,117 +68,72 @@ public class ElasticSearchMailboxModule extends AbstractModule {
     }
 
     @Provides
-    protected IndexName provideIndexName(ElasticSearchConfiguration elasticSearchConfiguration)
-            throws ConfigurationException {
+    @Singleton
+    private ElasticSearchConfiguration getElasticSearchConfiguration(PropertiesProvider propertiesProvider) throws ConfigurationException {
         try {
-            return Optional.ofNullable(elasticSearchConfiguration.getConfiguration()
-                .getString("elasticsearch.index.name"))
-                .map(IndexName::new)
-                .orElse(MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX);
+            PropertiesConfiguration configuration = propertiesProvider.getConfiguration(ELASTICSEARCH_CONFIGURATION_NAME);
+            return ElasticSearchConfiguration.fromProperties(configuration);
         } catch (FileNotFoundException e) {
-            LOGGER.info("Could not find ElasticSearch configuration file. Using default index {}", MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX.getValue());
-            return MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX;
+            LOGGER.warn("Could not find " + ELASTICSEARCH_CONFIGURATION_NAME + " configuration file. Using 127.0.0.1:9300 as contact point");
+            PropertiesConfiguration configuration = new PropertiesConfiguration();
+            configuration.addProperty(ElasticSearchConfiguration.ELASTICSEARCH_HOSTS, LOCALHOST);
+            return ElasticSearchConfiguration.fromProperties(configuration);
         }
     }
 
     @Provides
-    protected AliasName provideAliasName(ElasticSearchConfiguration elasticSearchConfiguration)
-            throws ConfigurationException {
-        try {
-            return Optional.ofNullable(elasticSearchConfiguration.getConfiguration()
-                .getString("elasticsearch.alias.name"))
-                .map(AliasName::new)
-                .orElse(MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS);
-        } catch (FileNotFoundException e) {
-            LOGGER.info("Could not find ElasticSearch configuration file. Using default alias {}", MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX.getValue());
-            return MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS;
-        }
+    protected IndexName provideIndexName(ElasticSearchConfiguration configuration) {
+        return configuration.getIndexName();
     }
 
-    @Provides
-    @Singleton
-    protected Client provideClientProvider(ElasticSearchConfiguration elasticSearchConfiguration,
-                                           IndexName indexName, AliasName aliasName,
-                                           AsyncRetryExecutor executor) throws ConfigurationException, FileNotFoundException, ExecutionException, InterruptedException {
-        PropertiesConfiguration propertiesReader = elasticSearchConfiguration.getConfiguration();
-        int maxRetries = propertiesReader.getInt("elasticsearch.retryConnection.maxRetries", DEFAULT_CONNECTION_MAX_RETRIES);
-        int minDelay = propertiesReader.getInt("elasticsearch.retryConnection.minDelay", DEFAULT_CONNECTION_MIN_DELAY);
-
-        return RetryExecutorUtil.retryOnExceptions(executor, maxRetries, minDelay, NoNodeAvailableException.class)
-            .getWithRetry(context -> connectToCluster(propertiesReader, indexName, aliasName))
-            .get();
+    @Provides @Named(ElasticSearchConstants.READ_ALIAS)
+    protected AliasName provideReadAliasName(ElasticSearchConfiguration configuration) {
+        return configuration.getReadAliasName();
     }
 
-    private Client createIndexAndMapping(Client client, IndexName indexName, AliasName aliasName, PropertiesConfiguration propertiesReader) {
-        IndexCreationFactory.createIndexAndAlias(client,
-            indexName,
-            aliasName,
-            propertiesReader.getInt(ELASTICSEARCH_CONFIGURATION_NAME + ".nb.shards", DEFAULT_NB_SHARDS),
-            propertiesReader.getInt(ELASTICSEARCH_CONFIGURATION_NAME + ".nb.replica", DEFAULT_NB_REPLICA));
-        NodeMappingFactory.applyMapping(client,
-            MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX,
-            MailboxElasticsearchConstants.MESSAGE_TYPE,
-            MailboxMappingFactory.getMappingContent());
-        return client;
+    @Provides @Named(ElasticSearchConstants.WRITE_ALIAS)
+    protected AliasName provideWriteAliasName(ElasticSearchConfiguration configuration) {
+        return configuration.getWriteAliasName();
     }
 
-    private Client connectToCluster(PropertiesConfiguration propertiesReader, IndexName indexName, AliasName aliasName)
-            throws ConfigurationException {
-        LOGGER.info("Trying to connect to ElasticSearch service at {}", LocalDateTime.now());
-
-        return createIndexAndMapping(createClient(propertiesReader), indexName, aliasName, propertiesReader);
+    @Provides
+    @Singleton
+    protected IndexCreationFactory provideIndexCreationFactory(ElasticSearchConfiguration configuration) {
+        return new IndexCreationFactory()
+            .onIndex(configuration.getIndexName())
+            .addAlias(configuration.getReadAliasName())
+            .addAlias(configuration.getWriteAliasName())
+            .nbShards(configuration.getNbShards())
+            .nbReplica(configuration.getNbReplica());
     }
 
     @Provides
     @Singleton
-    private ElasticSearchConfiguration getElasticSearchConfiguration(PropertiesProvider propertiesProvider) throws ConfigurationException {
-        try {
-            PropertiesConfiguration configuration = propertiesProvider.getConfiguration(ELASTICSEARCH_CONFIGURATION_NAME);
-            return () -> configuration;
-        } catch (FileNotFoundException e) {
-            LOGGER.warn("Could not find " + ELASTICSEARCH_CONFIGURATION_NAME + " configuration file. Using 127.0.0.1:9300 as contact point");
-            PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration();
-            propertiesConfiguration.addProperty(ELASTICSEARCH_HOSTS, LOCALHOST);
-            return () -> propertiesConfiguration;
-        }
+    protected Client provideClientProvider(ElasticSearchConfiguration configuration,
+                                           IndexCreationFactory indexCreationFactory,
+                                           AsyncRetryExecutor executor) throws ExecutionException, InterruptedException {
+
+        return RetryExecutorUtil.retryOnExceptions(executor, configuration.getMaxRetries(), configuration.getMinDelay(), NoNodeAvailableException.class)
+            .getWithRetry(context -> connectToCluster(configuration, indexCreationFactory))
+            .get();
     }
 
-    private Client createClient(PropertiesConfiguration propertiesReader) throws ConfigurationException {
-        Optional<String> monoHostAddress = Optional.ofNullable(propertiesReader.getString(ELASTICSEARCH_MASTER_HOST, null));
-        Optional<Integer> monoHostPort = Optional.ofNullable(propertiesReader.getInteger(ELASTICSEARCH_PORT, null));
-        Optional<String> multiHosts = Optional.ofNullable(propertiesReader.getString(ELASTICSEARCH_HOSTS, null));
+    private Client connectToCluster(ElasticSearchConfiguration configuration, IndexCreationFactory indexCreationFactory) {
+        LOGGER.info("Trying to connect to ElasticSearch service at {}", LocalDateTime.now());
 
-        validateHostsConfigurationOptions(monoHostAddress, monoHostPort, multiHosts);
+        Client client = ClientProviderImpl.fromHosts(configuration.getHosts()).get();
 
-        if (monoHostAddress.isPresent()) {
-            return ClientProviderImpl.forHost(monoHostAddress.get(), monoHostPort.get()).get();
-        } else {
-            return ClientProviderImpl.fromHostsString(multiHosts.get()).get();
-        }
-    }
-
-    @VisibleForTesting
-    static void validateHostsConfigurationOptions(Optional<String> monoHostAddress,
-                                                          Optional<Integer> monoHostPort,
-                                                          Optional<String> multiHosts) throws ConfigurationException {
-        if (monoHostAddress.isPresent() != monoHostPort.isPresent()) {
-            throw new ConfigurationException(ELASTICSEARCH_MASTER_HOST + " and " + ELASTICSEARCH_PORT + " should be specified together");
-        }
-        if (multiHosts.isPresent() && monoHostAddress.isPresent()) {
-            throw new ConfigurationException("You should choose between mono host set up and " + ELASTICSEARCH_HOSTS);
-        }
-        if (!multiHosts.isPresent() && !monoHostAddress.isPresent()) {
-            throw new ConfigurationException("You should specify either (" + ELASTICSEARCH_MASTER_HOST + " and " + ELASTICSEARCH_PORT + ") or " + ELASTICSEARCH_HOSTS);
-        }
+        indexCreationFactory.createIndexAndAliases(client);
+        return NodeMappingFactory.applyMapping(client,
+            configuration.getIndexName(),
+            MailboxElasticsearchConstants.MESSAGE_TYPE,
+            MailboxMappingFactory.getMappingContent());
     }
 
     @Provides
     @Singleton
-    public IndexAttachments provideIndexAttachments(PropertiesConfiguration configuration) {
-        if (configuration.getBoolean(ELASTICSEARCH_CONFIGURATION_NAME + ".indexAttachments", DEFAULT_INDEX_ATTACHMENTS)) {
-            return IndexAttachments.YES;
-        }
-        return IndexAttachments.NO;
+    public IndexAttachments provideIndexAttachments(ElasticSearchConfiguration configuration) {
+        return configuration.getIndexAttachment();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/server/container/guice/cassandra-guice/src/test/java/org/apache/james/DockerElasticSearchRule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/DockerElasticSearchRule.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/DockerElasticSearchRule.java
index 75fe4a3..85171ba 100644
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/DockerElasticSearchRule.java
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/DockerElasticSearchRule.java
@@ -19,12 +19,14 @@
 
 package org.apache.james;
 
+import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.PropertiesConfiguration;
 import org.apache.james.modules.mailbox.ElasticSearchConfiguration;
 import org.apache.james.util.streams.SwarmGenericContainer;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
+import com.google.common.base.Throwables;
 import com.google.inject.Module;
 
 
@@ -33,7 +35,7 @@ public class DockerElasticSearchRule implements GuiceModuleTestRule {
     private static final int ELASTIC_SEARCH_PORT = 9300;
     public static final int ELASTIC_SEARCH_HTTP_PORT = 9200;
 
-    public PropertiesConfiguration getElasticSearchConfigurationForDocker() {
+    public ElasticSearchConfiguration getElasticSearchConfigurationForDocker() {
         PropertiesConfiguration configuration = new PropertiesConfiguration();
 
         configuration.addProperty("elasticsearch.masterHost", getIp());
@@ -50,7 +52,11 @@ public class DockerElasticSearchRule implements GuiceModuleTestRule {
         configuration.addProperty("elasticsearch.metrics.reports.period", 30);
         configuration.addProperty("elasticsearch.metrics.reports.index", "james-metrics");
 
-        return configuration;
+        try {
+            return ElasticSearchConfiguration.fromProperties(configuration);
+        } catch (ConfigurationException e) {
+            throw Throwables.propagate(e);
+        }
     }
 
     private SwarmGenericContainer elasticSearchContainer = new SwarmGenericContainer("elasticsearch:2.2.2")
@@ -67,7 +73,9 @@ public class DockerElasticSearchRule implements GuiceModuleTestRule {
 
     @Override
     public Module getModule() {
-        return (binder) -> binder.bind(ElasticSearchConfiguration.class).toInstance(this::getElasticSearchConfigurationForDocker);
+        return (binder) ->
+                binder.bind(ElasticSearchConfiguration.class)
+                    .toInstance(getElasticSearchConfigurationForDocker());
     }
 
     public String getIp() {

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/TestElasticSearchModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/TestElasticSearchModule.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/TestElasticSearchModule.java
index 2b6b272..5e30618 100644
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/TestElasticSearchModule.java
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/TestElasticSearchModule.java
@@ -49,9 +49,12 @@ public class TestElasticSearchModule extends AbstractModule{
     @Singleton
     protected Client provideClientProvider() {
         Client client = new TestingClientProvider(embeddedElasticSearch.getNode()).get();
-        IndexCreationFactory.createIndexAndAlias(client,
-            MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX,
-            MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS);
+
+        new IndexCreationFactory()
+            .onIndex(MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX)
+            .addAlias(MailboxElasticsearchConstants.DEFAULT_MAILBOX_READ_ALIAS)
+            .addAlias(MailboxElasticsearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS)
+            .createIndexAndAliases(client);
         return NodeMappingFactory.applyMapping(client,
             MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX,
             MailboxElasticsearchConstants.MESSAGE_TYPE,

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchConfigurationTest.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchConfigurationTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchConfigurationTest.java
new file mode 100644
index 0000000..f4b7765
--- /dev/null
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchConfigurationTest.java
@@ -0,0 +1,347 @@
+/****************************************************************
+ * 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.modules.mailbox;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.Optional;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.james.backends.es.AliasName;
+import org.apache.james.backends.es.IndexName;
+import org.apache.james.mailbox.elasticsearch.IndexAttachments;
+import org.apache.james.mailbox.elasticsearch.MailboxElasticsearchConstants;
+import org.apache.james.util.Host;
+import org.junit.Test;
+
+public class ElasticSearchConfigurationTest {
+
+    @Test
+    public void getNbReplicaShouldReturnConfiguredValue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        int value = 36;
+        configuration.addProperty("elasticsearch.nb.replica", value);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getNbReplica())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void getNbReplicaShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getNbReplica())
+            .isEqualTo(ElasticSearchConfiguration.DEFAULT_NB_REPLICA);
+    }
+
+    @Test
+    public void getNbShardsShouldReturnConfiguredValue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        int value = 36;
+        configuration.addProperty("elasticsearch.nb.shards", value);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getNbShards())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void getNbShardsShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getNbShards())
+            .isEqualTo(ElasticSearchConfiguration.DEFAULT_NB_SHARDS);
+    }
+
+    @Test
+    public void getMaxRetriesShouldReturnConfiguredValue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        int value = 36;
+        configuration.addProperty("elasticsearch.retryConnection.maxRetries", value);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getMaxRetries())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void getMaxRetriesShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getMaxRetries())
+            .isEqualTo(ElasticSearchConfiguration.DEFAULT_CONNECTION_MAX_RETRIES);
+    }
+
+    @Test
+    public void getMinDelayShouldReturnConfiguredValue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        int value = 36;
+        configuration.addProperty("elasticsearch.retryConnection.minDelay", value);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getMinDelay())
+            .isEqualTo(value);
+    }
+
+    @Test
+    public void getMinDelayShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getMinDelay())
+            .isEqualTo(ElasticSearchConfiguration.DEFAULT_CONNECTION_MIN_DELAY);
+    }
+
+    @Test
+    public void getIndexNameShouldReturnConfiguredValue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.index.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexName())
+            .isEqualTo(new IndexName(name));
+    }
+
+    @Test
+    public void getIndexNameShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexName())
+            .isEqualTo(MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX);
+    }
+
+    @Test
+    public void getReadAliasNameShouldReturnConfiguredValue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.alias.read.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getReadAliasName())
+            .isEqualTo(new AliasName(name));
+    }
+
+    @Test
+    public void getReadAliasNameShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getReadAliasName())
+            .isEqualTo(MailboxElasticsearchConstants.DEFAULT_MAILBOX_READ_ALIAS);
+    }
+
+
+    @Test
+    public void getWriteAliasNameNameShouldReturnConfiguredValue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.alias.write.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getWriteAliasName())
+            .isEqualTo(new AliasName(name));
+    }
+
+    @Test
+    public void getWriteAliasNameShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getWriteAliasName())
+            .isEqualTo(MailboxElasticsearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS);
+    }
+
+    @Test
+    public void getIndexAttachmentShouldReturnConfiguredValueWhenTrue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.indexAttachments", true);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexAttachment())
+            .isEqualTo(IndexAttachments.YES);
+    }
+
+    @Test
+    public void getIndexAttachmentShouldReturnConfiguredValueWhenFalse() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.indexAttachments", false);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexAttachment())
+            .isEqualTo(IndexAttachments.NO);
+    }
+
+    @Test
+    public void getIndexAttachmentShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexAttachment())
+            .isEqualTo(IndexAttachments.YES);
+    }
+
+
+    @Test
+    public void getHostsShouldReturnConfiguredHostsWhenNoPort() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String hostname = "myHost";
+        configuration.addProperty("elasticsearch.hosts", hostname);
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getHosts())
+            .containsOnly(Host.from(hostname, ElasticSearchConfiguration.DEFAULT_PORT));
+    }
+
+    @Test
+    public void getHostsShouldReturnConfiguredHosts() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String hostname = "myHost";
+        int port = 2154;
+        configuration.addProperty("elasticsearch.hosts", hostname + ":" + port);
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getHosts())
+            .containsOnly(Host.from(hostname, port));
+    }
+
+    @Test
+    public void getHostsShouldReturnConfiguredMasterHost() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String hostname = "myHost";
+        configuration.addProperty("elasticsearch.masterHost", hostname);
+        int port = 9300;
+        configuration.addProperty("elasticsearch.port", port);
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getHosts())
+            .containsOnly(Host.from(hostname, port));
+    }
+
+    @Test
+    public void validateHostsConfigurationOptionsShouldThrowWhenNoHostSpecify() throws Exception {
+        assertThatThrownBy(() ->
+            ElasticSearchConfiguration.validateHostsConfigurationOptions(
+                Optional.empty(),
+                Optional.empty(),
+                Optional.empty()))
+            .isInstanceOf(ConfigurationException.class)
+            .hasMessage("You should specify either (" + ElasticSearchConfiguration.ELASTICSEARCH_MASTER_HOST +
+                " and " + ElasticSearchConfiguration.ELASTICSEARCH_PORT +
+                ") or " + ElasticSearchConfiguration.ELASTICSEARCH_HOSTS);
+    }
+
+    @Test
+    public void validateHostsConfigurationOptionsShouldThrowWhenMonoAndMultiHostSpecified() throws Exception {
+        assertThatThrownBy(() ->
+            ElasticSearchConfiguration.validateHostsConfigurationOptions(
+                Optional.of("localhost"),
+                Optional.of(9200),
+                Optional.of("localhost:9200")))
+            .isInstanceOf(ConfigurationException.class)
+            .hasMessage("You should choose between mono host set up and " + ElasticSearchConfiguration.ELASTICSEARCH_HOSTS);
+    }
+
+    @Test
+    public void validateHostsConfigurationOptionsShouldThrowWhenMonoHostWithoutPort() throws Exception {
+        assertThatThrownBy(() ->
+            ElasticSearchConfiguration.validateHostsConfigurationOptions(
+                Optional.of("localhost"),
+                Optional.empty(),
+                Optional.empty()))
+            .isInstanceOf(ConfigurationException.class)
+            .hasMessage(ElasticSearchConfiguration.ELASTICSEARCH_MASTER_HOST +
+                " and " + ElasticSearchConfiguration.ELASTICSEARCH_PORT + " should be specified together");
+    }
+
+    @Test
+    public void validateHostsConfigurationOptionsShouldThrowWhenMonoHostWithoutAddress() throws Exception {
+        assertThatThrownBy(() ->
+        ElasticSearchConfiguration.validateHostsConfigurationOptions(
+            Optional.empty(),
+            Optional.of(9200),
+            Optional.empty()))
+        .isInstanceOf(ConfigurationException.class)
+        .hasMessage(ElasticSearchConfiguration.ELASTICSEARCH_MASTER_HOST + " and " +
+            ElasticSearchConfiguration.ELASTICSEARCH_PORT + " should be specified together");
+    }
+
+    @Test
+    public void validateHostsConfigurationOptionsShouldAcceptMonoHostConfiguration() throws Exception {
+        ElasticSearchConfiguration.validateHostsConfigurationOptions(
+            Optional.of("localhost"),
+            Optional.of(9200),
+            Optional.empty());
+    }
+
+    @Test
+    public void validateHostsConfigurationOptionsShouldAcceptMultiHostConfiguration() throws Exception {
+        ElasticSearchConfiguration.validateHostsConfigurationOptions(
+            Optional.empty(),
+            Optional.empty(),
+            Optional.of("localhost:9200"));
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModuleTest.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModuleTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModuleTest.java
deleted file mode 100644
index 41108e7..0000000
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModuleTest.java
+++ /dev/null
@@ -1,215 +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.modules.mailbox;
-
-import static org.apache.james.modules.mailbox.ElasticSearchMailboxModule.ELASTICSEARCH_HOSTS;
-import static org.apache.james.modules.mailbox.ElasticSearchMailboxModule.ELASTICSEARCH_MASTER_HOST;
-import static org.apache.james.modules.mailbox.ElasticSearchMailboxModule.ELASTICSEARCH_PORT;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.io.FileNotFoundException;
-import java.util.Optional;
-
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.apache.james.backends.es.AliasName;
-import org.apache.james.backends.es.IndexName;
-import org.apache.james.mailbox.elasticsearch.IndexAttachments;
-import org.apache.james.mailbox.elasticsearch.MailboxElasticsearchConstants;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-public class ElasticSearchMailboxModuleTest {
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Test
-    public void provideIndexNameShouldRetrievedConfiguredIndexName() throws ConfigurationException {
-        PropertiesConfiguration configuration = new PropertiesConfiguration();
-        String name = "name";
-        configuration.addProperty("elasticsearch.index.name", name);
-
-        ElasticSearchMailboxModule testee = new ElasticSearchMailboxModule();
-
-        IndexName indexName = testee.provideIndexName(() -> configuration);
-
-        assertThat(indexName)
-            .isEqualTo(new IndexName(name));
-    }
-
-    @Test
-    public void provideIndexNameShouldReturnDefaultIndexNameWhenNone() throws ConfigurationException {
-        PropertiesConfiguration configuration = new PropertiesConfiguration();
-
-        ElasticSearchMailboxModule testee = new ElasticSearchMailboxModule();
-
-        IndexName indexName = testee.provideIndexName(() -> configuration);
-
-        assertThat(indexName)
-            .isEqualTo(MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX);
-    }
-
-    @Test
-    public void provideIndexNameShouldReturnDefaultIndexNameWhenError() throws ConfigurationException {
-        ElasticSearchMailboxModule testee = new ElasticSearchMailboxModule();
-
-        IndexName indexName = testee.provideIndexName(() -> {
-            throw new FileNotFoundException();
-        });
-
-        assertThat(indexName)
-            .isEqualTo(MailboxElasticsearchConstants.DEFAULT_MAILBOX_INDEX);
-    }
-
-    @Test
-    public void provideAliasNameShouldRetrievedConfiguredAliasName() throws ConfigurationException {
-        PropertiesConfiguration configuration = new PropertiesConfiguration();
-        String name = "name";
-        configuration.addProperty("elasticsearch.alias.name", name);
-
-        ElasticSearchMailboxModule testee = new ElasticSearchMailboxModule();
-
-        AliasName indexName = testee.provideAliasName(() -> configuration);
-
-        assertThat(indexName)
-            .isEqualTo(new AliasName(name));
-    }
-
-    @Test
-    public void provideAliasNameShouldReturnDefaultAliasNameWhenNone() throws ConfigurationException {
-        PropertiesConfiguration configuration = new PropertiesConfiguration();
-
-        ElasticSearchMailboxModule testee = new ElasticSearchMailboxModule();
-
-        AliasName aliasName = testee.provideAliasName(() -> configuration);
-
-        assertThat(aliasName)
-            .isEqualTo(MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS);
-    }
-
-    @Test
-    public void provideAliasNameShouldReturnDefaultAliasNameWhenError() throws ConfigurationException {
-        ElasticSearchMailboxModule testee = new ElasticSearchMailboxModule();
-
-        AliasName aliasName = testee.provideAliasName(() -> {
-            throw new FileNotFoundException();
-        });
-
-        assertThat(aliasName)
-            .isEqualTo(MailboxElasticsearchConstants.DEFAULT_MAILBOX_ALIAS);
-    }
-
-    @Test
-    public void provideIndexAttachmentsShouldReturnTrueWhenIndexAttachmentsIsTrueInConfiguration() {
-        PropertiesConfiguration configuration = new PropertiesConfiguration();
-        configuration.addProperty("elasticsearch.indexAttachments", true);
-
-        ElasticSearchMailboxModule testee = new ElasticSearchMailboxModule();
-
-        IndexAttachments indexAttachments = testee.provideIndexAttachments(configuration);
-
-        assertThat(indexAttachments).isEqualTo(IndexAttachments.YES);
-    }
-
-    @Test
-    public void provideIndexAttachmentsShouldReturnFalseWhenIndexAttachmentsIsFalseInConfiguration() {
-        PropertiesConfiguration configuration = new PropertiesConfiguration();
-        configuration.addProperty("elasticsearch.indexAttachments", false);
-
-        ElasticSearchMailboxModule testee = new ElasticSearchMailboxModule();
-
-        IndexAttachments indexAttachments = testee.provideIndexAttachments(configuration);
-
-        assertThat(indexAttachments).isEqualTo(IndexAttachments.NO);
-    }
-
-    @Test
-    public void provideIndexAttachmentsShouldReturnTrueWhenIndexAttachmentsIsNotDefinedInConfiguration() {
-        PropertiesConfiguration configuration = new PropertiesConfiguration();
-
-        ElasticSearchMailboxModule testee = new ElasticSearchMailboxModule();
-
-        IndexAttachments indexAttachments = testee.provideIndexAttachments(configuration);
-
-        assertThat(indexAttachments).isEqualTo(IndexAttachments.YES);
-    }
-
-    @Test
-    public void validateHostsConfigurationOptionsShouldThrowWhenNoHostSpecify() throws Exception {
-        expectedException.expect(ConfigurationException.class);
-        expectedException.expectMessage("You should specify either (" + ELASTICSEARCH_MASTER_HOST + " and " + ELASTICSEARCH_PORT + ") or " + ELASTICSEARCH_HOSTS);
-
-        ElasticSearchMailboxModule.validateHostsConfigurationOptions(
-            Optional.empty(),
-            Optional.empty(),
-            Optional.empty());
-    }
-
-    @Test
-    public void validateHostsConfigurationOptionsShouldThrowWhenMonoAndMultiHostSpecified() throws Exception {
-        expectedException.expect(ConfigurationException.class);
-        expectedException.expectMessage("You should choose between mono host set up and " + ELASTICSEARCH_HOSTS);
-
-        ElasticSearchMailboxModule.validateHostsConfigurationOptions(
-            Optional.of("localhost"),
-            Optional.of(9200),
-            Optional.of("localhost:9200"));
-    }
-
-    @Test
-    public void validateHostsConfigurationOptionsShouldThrowWhenMonoHostWithoutPort() throws Exception {
-        expectedException.expect(ConfigurationException.class);
-        expectedException.expectMessage(ELASTICSEARCH_MASTER_HOST + " and " + ELASTICSEARCH_PORT + " should be specified together");
-
-        ElasticSearchMailboxModule.validateHostsConfigurationOptions(
-            Optional.of("localhost"),
-            Optional.empty(),
-            Optional.empty());
-    }
-
-    @Test
-    public void validateHostsConfigurationOptionsShouldThrowWhenMonoHostWithoutAddress() throws Exception {
-        expectedException.expect(ConfigurationException.class);
-        expectedException.expectMessage(ELASTICSEARCH_MASTER_HOST + " and " + ELASTICSEARCH_PORT + " should be specified together");
-
-        ElasticSearchMailboxModule.validateHostsConfigurationOptions(
-            Optional.empty(),
-            Optional.of(9200),
-            Optional.empty());
-    }
-
-    @Test
-    public void validateHostsConfigurationOptionsShouldAcceptMonoHostConfiguration() throws Exception {
-        ElasticSearchMailboxModule.validateHostsConfigurationOptions(
-            Optional.of("localhost"),
-            Optional.of(9200),
-            Optional.empty());
-    }
-
-    @Test
-    public void validateHostsConfigurationOptionsShouldAcceptMultiHostConfiguration() throws Exception {
-        ElasticSearchMailboxModule.validateHostsConfigurationOptions(
-            Optional.empty(),
-            Optional.empty(),
-            Optional.of("localhost:9200"));
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/server/container/util-java8/src/main/java/org/apache/james/util/Host.java
----------------------------------------------------------------------
diff --git a/server/container/util-java8/src/main/java/org/apache/james/util/Host.java b/server/container/util-java8/src/main/java/org/apache/james/util/Host.java
index 3927c73..4776f06 100644
--- a/server/container/util-java8/src/main/java/org/apache/james/util/Host.java
+++ b/server/container/util-java8/src/main/java/org/apache/james/util/Host.java
@@ -123,7 +123,8 @@ public class Host {
     public final boolean equals(Object object) {
         if (object instanceof Host) {
             Host that = (Host) object;
-            return Objects.equal(this.hostName, that.hostName) && Objects.equal(this.port, that.port);
+            return Objects.equal(this.hostName, that.hostName)
+                && Objects.equal(this.port, that.port);
         }
         return false;
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f3b6ac5d/src/site/xdoc/server/config-elasticsearch.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/server/config-elasticsearch.xml b/src/site/xdoc/server/config-elasticsearch.xml
index 2b9ad23..b5ca6c8 100644
--- a/src/site/xdoc/server/config-elasticsearch.xml
+++ b/src/site/xdoc/server/config-elasticsearch.xml
@@ -58,9 +58,12 @@
           <dd>Number of replica for index provisionned by James</dd>
           <dt><strong>elasticsearch.index.name</strong></dt>
           <dd>Name of the index backed by the alias. It will be created if missing.</dd>
-          <dt><strong>elasticsearch.alias.name</strong></dt>
-          <dd>Name of the alias to use with Apache James. It will be created if missing.
-           The target of the alias is the index name configured above.</dd>
+          <dt><strong>elasticsearch.alias.read.name</strong></dt>
+          <dd>Name of the alias to use by Apache James for reads. It will be created if missing.
+              The target of the alias is the index name configured above.</dd>
+          <dt><strong>elasticsearch.alias.write.name</strong></dt>
+          <dd>Name of the alias to use by Apache James for writes. It will be created if missing.
+              The target of the alias is the index name configured above.</dd>
           <dt><strong>elasticsearch.retryConnection.maxRetries</strong></dt>
           <dd>Number of retries when connecting the cluster</dd>
           <dt><strong>elasticsearch.retryConnection.minDelay</strong></dt>


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


Mime
View raw message