james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From btell...@apache.org
Subject [06/10] james-project git commit: JAMES-2441 Rely on POJO for Cassandra configuration
Date Mon, 02 Jul 2018 04:49:32 GMT
JAMES-2441 Rely on POJO for Cassandra configuration

It allows to inject directly the POJO we want without to care about their file representation.

Furthermore, we can reduce the testing scope of some classes, we can also better split responsibilities between classes.


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

Branch: refs/heads/master
Commit: c767bf797b1dd587ef608199ba8b3c9bf7d07257
Parents: 02301a6
Author: benwa <btellier@linagora.com>
Authored: Wed Jun 27 17:18:38 2018 +0700
Committer: benwa <btellier@linagora.com>
Committed: Mon Jul 2 11:48:52 2018 +0700

----------------------------------------------------------------------
 .../cassandra/init/CassandraConfiguration.java  | 338 ----------------
 .../backends/cassandra/init/ClusterBuilder.java |   1 +
 .../init/QueryLoggerConfiguration.java          | 136 -------
 .../SessionWithInitializedTablesFactory.java    |  11 +-
 .../configuration/CassandraConfiguration.java   | 384 +++++++++++++++++++
 .../configuration/ClusterConfiguration.java     | 311 +++++++++++++++
 .../configuration/QueryLoggerConfiguration.java | 191 +++++++++
 .../cassandra/utils/CassandraUtils.java         |   2 +-
 .../backends/cassandra/CassandraCluster.java    |  26 +-
 .../init/CassandraConfigurationReadingTest.java |  60 +++
 .../init/CassandraConfigurationTest.java        |   1 +
 .../init/QueryLoggerConfigurationTest.java      |  62 +++
 .../src/test/resources/cassandra.properties     |  12 +
 .../CassandraMailboxSessionMapperFactory.java   |   2 +-
 .../cassandra/mail/CassandraACLMapper.java      |   2 +-
 .../cassandra/mail/CassandraAttachmentDAO.java  |   2 +-
 .../cassandra/mail/CassandraMessageDAO.java     |   2 +-
 .../mail/CassandraMessageIdMapper.java          |   2 +-
 .../cassandra/mail/CassandraMessageMapper.java  |   2 +-
 .../cassandra/mail/CassandraModSeqProvider.java |   2 +-
 .../cassandra/mail/CassandraUidProvider.java    |   2 +-
 .../CassandraSubscriptionManagerTest.java       |   2 +-
 ...estCassandraMailboxSessionMapperFactory.java |   2 +-
 .../cassandra/mail/CassandraACLMapperTest.java  |   2 +-
 .../mail/CassandraAttachmentDAOTest.java        |   2 +-
 .../mail/CassandraAttachmentFallbackTest.java   |   2 +-
 .../CassandraMailboxMapperConcurrencyTest.java  |   2 +-
 .../mail/CassandraMailboxMapperTest.java        |   2 +-
 .../mail/CassandraMessageIdMapperTest.java      |   2 +-
 .../migration/AttachmentV2MigrationTest.java    |   2 +-
 .../migration/MailboxPathV2MigrationTest.java   |   2 +-
 .../james/blob/cassandra/CassandraBlobsDAO.java |   2 +-
 .../blob/cassandra/CassandraBlobsDAOTest.java   |   2 +-
 .../modules/mailbox/CassandraSessionModule.java |  60 +--
 .../mailbox/ResilientClusterProvider.java       | 139 +------
 .../org/apache/james/server/CassandraProbe.java |  14 +-
 .../james/CassandraLogConfigurationTest.java    | 131 -------
 .../org/apache/james/CassandraNodeConfTest.java |  40 +-
 .../org/apache/james/DockerCassandraRule.java   |  29 +-
 .../mailbox/CassandraSessionModuleTest.java     |  68 ----
 40 files changed, 1119 insertions(+), 937 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraConfiguration.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraConfiguration.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraConfiguration.java
deleted file mode 100644
index 10764a5..0000000
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/CassandraConfiguration.java
+++ /dev/null
@@ -1,338 +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.backends.cassandra.init;
-
-import static java.lang.Math.toIntExact;
-
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
-
-public class CassandraConfiguration {
-    public static final int DEFAULT_MESSAGE_CHUNK_SIZE_ON_READ = 100;
-    public static final int DEFAULT_EXPUNGE_BATCH_SIZE = 100;
-    public static final int DEFAULT_UPDATE_FLAGS_BATCH_SIZE = 20;
-    public static final int DEFAULT_FLAGS_UPDATE_MESSAGE_MAX_RETRY = 1000;
-    public static final int DEFAULT_FLAGS_UPDATE_MESSAGE_ID_MAX_RETRY = 1000;
-    public static final int DEFAULT_MODSEQ_MAX_RETRY = 100000;
-    public static final int DEFAULT_UID_MAX_RETRY = 100000;
-    public static final int DEFAULT_ACL_MAX_RETRY = 1000;
-    public static final int DEFAULT_FETCH_NEXT_PAGE_ADVANCE_IN_ROW = 100;
-    public static final int DEFAULT_BLOB_PART_SIZE = 100 * 1024;
-    public static final int DEFAULT_ATTACHMENT_V2_MIGRATION_READ_TIMEOUT = toIntExact(TimeUnit.HOURS.toMillis(1));
-    public static final int DEFAULT_MESSAGE_ATTACHMENT_ID_MIGRATION_READ_TIMEOUT = toIntExact(TimeUnit.HOURS.toMillis(1));
-    public static final CassandraConfiguration DEFAULT_CONFIGURATION = builder().build();
-
-    public static class Builder {
-        private Optional<Integer> messageReadChunkSize = Optional.empty();
-        private Optional<Integer> expungeChunkSize = Optional.empty();
-        private Optional<Integer> flagsUpdateChunkSize = Optional.empty();
-        private Optional<Integer> flagsUpdateMessageIdMaxRetry = Optional.empty();
-        private Optional<Integer> flagsUpdateMessageMaxRetry = Optional.empty();
-        private Optional<Integer> modSeqMaxRetry = Optional.empty();
-        private Optional<Integer> uidMaxRetry = Optional.empty();
-        private Optional<Integer> aclMaxRetry = Optional.empty();
-        private Optional<Integer> fetchNextPageInAdvanceRow = Optional.empty();
-        private Optional<Integer> blobPartSize = Optional.empty();
-        private Optional<Integer> attachmentV2MigrationReadTimeout = Optional.empty();
-        private Optional<Integer> messageAttachmentIdsReadTimeout = Optional.empty();
-
-        public Builder messageReadChunkSize(int value) {
-            Preconditions.checkArgument(value > 0, "messageReadChunkSize needs to be strictly positive");
-            this.messageReadChunkSize = Optional.of(value);
-            return this;
-        }
-
-        public Builder expungeChunkSize(int value) {
-            Preconditions.checkArgument(value > 0, "expungeChunkSize needs to be strictly positive");
-            this.expungeChunkSize = Optional.of(value);
-            return this;
-        }
-
-        public Builder flagsUpdateChunkSize(int value) {
-            Preconditions.checkArgument(value > 0, "flagsUpdateChunkSize needs to be strictly positive");
-            this.flagsUpdateChunkSize = Optional.of(value);
-            return this;
-        }
-
-        public Builder flagsUpdateMessageIdMaxRetry(int value) {
-            Preconditions.checkArgument(value > 0, "flagsUpdateMessageIdMaxRetry needs to be strictly positive");
-            this.flagsUpdateMessageIdMaxRetry = Optional.of(value);
-            return this;
-        }
-
-        public Builder flagsUpdateMessageMaxRetry(int value) {
-            Preconditions.checkArgument(value > 0, "flagsUpdateMessageMaxRetry needs to be strictly positive");
-            this.flagsUpdateMessageMaxRetry = Optional.of(value);
-            return this;
-        }
-
-        public Builder modSeqMaxRetry(int value) {
-            Preconditions.checkArgument(value > 0, "modSeqMaxRetry needs to be strictly positive");
-            this.modSeqMaxRetry = Optional.of(value);
-            return this;
-        }
-
-        public Builder uidMaxRetry(int value) {
-            Preconditions.checkArgument(value > 0, "uidMaxRetry needs to be strictly positive");
-            this.uidMaxRetry = Optional.of(value);
-            return this;
-        }
-
-        public Builder aclMaxRetry(int value) {
-            Preconditions.checkArgument(value > 0, "aclMaxRetry needs to be strictly positive");
-            this.aclMaxRetry = Optional.of(value);
-            return this;
-        }
-
-        public Builder fetchNextPageInAdvanceRow(int value) {
-            Preconditions.checkArgument(value > 0, "fetchNextPageInAdvanceRow needs to be strictly positive");
-            this.fetchNextPageInAdvanceRow = Optional.of(value);
-            return this;
-        }
-
-        public Builder blobPartSize(int value) {
-            Preconditions.checkArgument(value > 0, "blobPartSize needs to be strictly positive");
-            this.blobPartSize = Optional.of(value);
-            return this;
-        }
-
-        public Builder attachmentV2MigrationReadTimeout(int value) {
-            Preconditions.checkArgument(value > 0, "attachmentV2MigrationReadTimeout needs to be strictly positive");
-            this.attachmentV2MigrationReadTimeout = Optional.of(value);
-            return this;
-        }
-
-        public Builder messageAttachmentIdsReadTimeout(int value) {
-            Preconditions.checkArgument(value > 0, "messageAttachmentIdsReadTimeout needs to be strictly positive");
-            this.messageAttachmentIdsReadTimeout = Optional.of(value);
-            return this;
-        }
-
-        public Builder messageReadChunkSize(Optional<Integer> value) {
-            value.ifPresent(this::messageReadChunkSize);
-            return this;
-        }
-
-        public Builder expungeChunkSize(Optional<Integer> value) {
-            value.ifPresent(this::expungeChunkSize);
-            return this;
-        }
-
-        public Builder flagsUpdateChunkSize(Optional<Integer> value) {
-            value.ifPresent(this::flagsUpdateChunkSize);
-            return this;
-        }
-
-        public Builder flagsUpdateMessageIdMaxRetry(Optional<Integer> value) {
-            value.ifPresent(this::flagsUpdateMessageIdMaxRetry);
-            return this;
-        }
-
-        public Builder flagsUpdateMessageMaxRetry(Optional<Integer> value) {
-            value.ifPresent(this::flagsUpdateMessageMaxRetry);
-            return this;
-        }
-
-        public Builder modSeqMaxRetry(Optional<Integer> value) {
-            value.ifPresent(this::modSeqMaxRetry);
-            return this;
-        }
-
-        public Builder uidMaxRetry(Optional<Integer> value) {
-            value.ifPresent(this::uidMaxRetry);
-            return this;
-        }
-
-        public Builder aclMaxRetry(Optional<Integer> value) {
-            value.ifPresent(this::aclMaxRetry);
-            return this;
-        }
-
-        public Builder fetchNextPageInAdvanceRow(Optional<Integer> value) {
-            value.ifPresent(this::fetchNextPageInAdvanceRow);
-            return this;
-        }
-
-        public Builder blobPartSize(Optional<Integer> value) {
-            value.ifPresent(this::blobPartSize);
-            return this;
-        }
-
-        public Builder attachmentV2MigrationReadTimeout(Optional<Integer> value) {
-            value.ifPresent(this::attachmentV2MigrationReadTimeout);
-            return this;
-        }
-
-        public Builder messageAttachmentIdsReadTimeout(Optional<Integer> value) {
-            value.ifPresent(this::messageAttachmentIdsReadTimeout);
-            return this;
-        }
-
-        public CassandraConfiguration build() {
-            return new CassandraConfiguration(aclMaxRetry.orElse(DEFAULT_ACL_MAX_RETRY),
-                messageReadChunkSize.orElse(DEFAULT_MESSAGE_CHUNK_SIZE_ON_READ),
-                expungeChunkSize.orElse(DEFAULT_EXPUNGE_BATCH_SIZE),
-                flagsUpdateChunkSize.orElse(DEFAULT_UPDATE_FLAGS_BATCH_SIZE),
-                flagsUpdateMessageIdMaxRetry.orElse(DEFAULT_FLAGS_UPDATE_MESSAGE_ID_MAX_RETRY),
-                flagsUpdateMessageMaxRetry.orElse(DEFAULT_FLAGS_UPDATE_MESSAGE_MAX_RETRY),
-                modSeqMaxRetry.orElse(DEFAULT_MODSEQ_MAX_RETRY),
-                uidMaxRetry.orElse(DEFAULT_UID_MAX_RETRY),
-                fetchNextPageInAdvanceRow.orElse(DEFAULT_FETCH_NEXT_PAGE_ADVANCE_IN_ROW),
-                blobPartSize.orElse(DEFAULT_BLOB_PART_SIZE),
-                attachmentV2MigrationReadTimeout.orElse(DEFAULT_ATTACHMENT_V2_MIGRATION_READ_TIMEOUT),
-                messageAttachmentIdsReadTimeout.orElse(DEFAULT_MESSAGE_ATTACHMENT_ID_MIGRATION_READ_TIMEOUT));
-        }
-    }
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    private final int messageReadChunkSize;
-    private final int expungeChunkSize;
-    private final int flagsUpdateChunkSize;
-    private final int flagsUpdateMessageIdMaxRetry;
-    private final int flagsUpdateMessageMaxRetry;
-    private final int modSeqMaxRetry;
-    private final int uidMaxRetry;
-    private final int aclMaxRetry;
-    private final int fetchNextPageInAdvanceRow;
-    private final int blobPartSize;
-    private final int attachmentV2MigrationReadTimeout;
-    private final int messageAttachmentIdsReadTimeout;
-
-    @VisibleForTesting
-    CassandraConfiguration(int aclMaxRetry, int messageReadChunkSize, int expungeChunkSize,
-                           int flagsUpdateChunkSize, int flagsUpdateMessageIdMaxRetry, int flagsUpdateMessageMaxRetry,
-                           int modSeqMaxRetry, int uidMaxRetry, int fetchNextPageInAdvanceRow,
-                           int blobPartSize, final int attachmentV2MigrationReadTimeout, int messageAttachmentIdsReadTimeout) {
-        this.aclMaxRetry = aclMaxRetry;
-        this.messageReadChunkSize = messageReadChunkSize;
-        this.expungeChunkSize = expungeChunkSize;
-        this.flagsUpdateMessageIdMaxRetry = flagsUpdateMessageIdMaxRetry;
-        this.flagsUpdateMessageMaxRetry = flagsUpdateMessageMaxRetry;
-        this.modSeqMaxRetry = modSeqMaxRetry;
-        this.uidMaxRetry = uidMaxRetry;
-        this.fetchNextPageInAdvanceRow = fetchNextPageInAdvanceRow;
-        this.flagsUpdateChunkSize = flagsUpdateChunkSize;
-        this.blobPartSize = blobPartSize;
-        this.attachmentV2MigrationReadTimeout = attachmentV2MigrationReadTimeout;
-        this.messageAttachmentIdsReadTimeout = messageAttachmentIdsReadTimeout;
-    }
-
-    public int getBlobPartSize() {
-        return blobPartSize;
-    }
-
-    public int getFlagsUpdateChunkSize() {
-        return flagsUpdateChunkSize;
-    }
-
-    public int getAclMaxRetry() {
-        return aclMaxRetry;
-    }
-
-    public int getMessageReadChunkSize() {
-        return messageReadChunkSize;
-    }
-
-    public int getExpungeChunkSize() {
-        return expungeChunkSize;
-    }
-
-    public int getFlagsUpdateMessageIdMaxRetry() {
-        return flagsUpdateMessageIdMaxRetry;
-    }
-
-    public int getFlagsUpdateMessageMaxRetry() {
-        return flagsUpdateMessageMaxRetry;
-    }
-
-    public int getModSeqMaxRetry() {
-        return modSeqMaxRetry;
-    }
-
-    public int getUidMaxRetry() {
-        return uidMaxRetry;
-    }
-
-    public int getFetchNextPageInAdvanceRow() {
-        return fetchNextPageInAdvanceRow;
-    }
-
-    public int getAttachmentV2MigrationReadTimeout() {
-        return attachmentV2MigrationReadTimeout;
-    }
-
-    public int getMessageAttachmentIdsReadTimeout() {
-        return messageAttachmentIdsReadTimeout;
-    }
-
-    @Override
-    public final boolean equals(Object o) {
-        if (o instanceof CassandraConfiguration) {
-            CassandraConfiguration that = (CassandraConfiguration) o;
-
-            return Objects.equals(this.aclMaxRetry, that.aclMaxRetry)
-                && Objects.equals(this.messageReadChunkSize, that.messageReadChunkSize)
-                && Objects.equals(this.expungeChunkSize, that.expungeChunkSize)
-                && Objects.equals(this.flagsUpdateMessageIdMaxRetry, that.flagsUpdateMessageIdMaxRetry)
-                && Objects.equals(this.flagsUpdateMessageMaxRetry, that.flagsUpdateMessageMaxRetry)
-                && Objects.equals(this.modSeqMaxRetry, that.modSeqMaxRetry)
-                && Objects.equals(this.uidMaxRetry, that.uidMaxRetry)
-                && Objects.equals(this.flagsUpdateChunkSize, that.flagsUpdateChunkSize)
-                && Objects.equals(this.fetchNextPageInAdvanceRow, that.fetchNextPageInAdvanceRow)
-                && Objects.equals(this.blobPartSize, that.blobPartSize)
-                && Objects.equals(this.attachmentV2MigrationReadTimeout, that.attachmentV2MigrationReadTimeout)
-                && Objects.equals(this.messageAttachmentIdsReadTimeout, that.messageAttachmentIdsReadTimeout);
-        }
-        return false;
-    }
-
-    @Override
-    public final int hashCode() {
-        return Objects.hash(aclMaxRetry, messageReadChunkSize, expungeChunkSize, flagsUpdateMessageIdMaxRetry,
-            flagsUpdateMessageMaxRetry, modSeqMaxRetry, uidMaxRetry, fetchNextPageInAdvanceRow, flagsUpdateChunkSize,
-            blobPartSize, attachmentV2MigrationReadTimeout, messageAttachmentIdsReadTimeout);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this)
-            .add("aclMaxRetry", aclMaxRetry)
-            .add("messageReadChunkSize", messageReadChunkSize)
-            .add("expungeChunkSize", expungeChunkSize)
-            .add("flagsUpdateMessageIdMaxRetry", flagsUpdateMessageIdMaxRetry)
-            .add("flagsUpdateMessageMaxRetry", flagsUpdateMessageMaxRetry)
-            .add("modSeqMaxRetry", modSeqMaxRetry)
-            .add("fetchNextPageInAdvanceRow", fetchNextPageInAdvanceRow)
-            .add("flagsUpdateChunkSize", flagsUpdateChunkSize)
-            .add("uidMaxRetry", uidMaxRetry)
-            .add("blobPartSize", blobPartSize)
-            .add("attachmentV2MigrationReadTimeout", attachmentV2MigrationReadTimeout)
-            .add("messageAttachmentIdsReadTimeout", messageAttachmentIdsReadTimeout)
-            .toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterBuilder.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterBuilder.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterBuilder.java
index 1bcfe0d..7af4519 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterBuilder.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/ClusterBuilder.java
@@ -22,6 +22,7 @@ package org.apache.james.backends.cassandra.init;
 import java.util.Collection;
 import java.util.Optional;
 
+import org.apache.james.backends.cassandra.init.configuration.QueryLoggerConfiguration;
 import org.apache.james.util.Host;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/QueryLoggerConfiguration.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/QueryLoggerConfiguration.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/QueryLoggerConfiguration.java
deleted file mode 100644
index b519ca7..0000000
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/QueryLoggerConfiguration.java
+++ /dev/null
@@ -1,136 +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.backends.cassandra.init;
-
-import java.util.Optional;
-
-import com.datastax.driver.core.PerHostPercentileTracker;
-import com.datastax.driver.core.QueryLogger;
-import com.google.common.base.Preconditions;
-
-public class QueryLoggerConfiguration {
-    private final Optional<Long> constantThreshold;
-    private final Optional<PerHostPercentileTracker> percentileTracker;
-    private final Optional<Double> slowQueryLatencyThresholdPercentile;
-    private final Optional<Integer> maxLoggedParameters;
-    private final Optional<Integer> maxParameterValueLength;
-    private final Optional<Integer> maxQueryStringLength;
-
-    public static class Builder {
-        private Optional<Long> constantThreshold;
-        private Optional<PerHostPercentileTracker> percentileTracker;
-        private Optional<Double> slowQueryLatencyThresholdPercentile;
-        private Optional<Integer> maxLoggedParameters;
-        private Optional<Integer> maxParameterValueLength;
-        private Optional<Integer> maxQueryStringLength;
-
-        private Builder() {
-            constantThreshold = Optional.empty();
-            percentileTracker = Optional.empty();
-            slowQueryLatencyThresholdPercentile = Optional.empty();
-            maxLoggedParameters = Optional.empty();
-            maxParameterValueLength = Optional.empty();
-            maxQueryStringLength = Optional.empty();
-        }
-
-        public Builder withConstantThreshold(long constantThreshold) {
-            this.constantThreshold = Optional.of(constantThreshold);
-
-            return this;
-        }
-
-        public Builder withDynamicThreshold(PerHostPercentileTracker percentileTracker,
-                                            double slowQueryLatencyThresholdPercentile) {
-            this.percentileTracker = Optional.of(percentileTracker);
-            this.slowQueryLatencyThresholdPercentile = Optional.of(slowQueryLatencyThresholdPercentile);
-
-            return this;
-        }
-
-        public Builder withMaxLoggedParameters(int maxLoggedParameters) {
-            this.maxLoggedParameters = Optional.of(maxLoggedParameters);
-
-            return this;
-        }
-
-        public Builder withMaxParameterValueLength(int maxParameterValueLength) {
-            this.maxParameterValueLength = Optional.of(maxParameterValueLength);
-
-            return this;
-        }
-
-        public Builder withMaxQueryStringLength(int maxQueryStringLength) {
-            this.maxQueryStringLength = Optional.of(maxQueryStringLength);
-
-            return this;
-        }
-
-        public QueryLoggerConfiguration build() {
-            Preconditions.checkState(!(constantThreshold.isPresent() && percentileTracker.isPresent()),
-                "You can not use slowQueryLatencyTheresholdMillis and percentileTracker at the same time");
-
-            return new QueryLoggerConfiguration(
-                constantThreshold,
-                percentileTracker,
-                slowQueryLatencyThresholdPercentile,
-                maxLoggedParameters,
-                maxParameterValueLength,
-                maxQueryStringLength
-            );
-        }
-    }
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    private QueryLoggerConfiguration(
-        Optional<Long> constantThreshold,
-        Optional<PerHostPercentileTracker> percentileTracker,
-        Optional<Double> slowQueryLatencyThresholdPercentile,
-        Optional<Integer> maxLoggedParameters,
-        Optional<Integer> maxParameterValueLength,
-        Optional<Integer> maxQueryStringLength) {
-        this.constantThreshold = constantThreshold;
-        this.percentileTracker = percentileTracker;
-        this.slowQueryLatencyThresholdPercentile = slowQueryLatencyThresholdPercentile;
-        this.maxLoggedParameters = maxLoggedParameters;
-        this.maxParameterValueLength = maxParameterValueLength;
-        this.maxQueryStringLength = maxQueryStringLength;
-    }
-
-    public QueryLogger getQueryLogger() {
-        QueryLogger.Builder builder = QueryLogger.builder();
-
-        percentileTracker.map(percentileTracker ->
-            slowQueryLatencyThresholdPercentile.map(slowQueryLatencyThresholdPercentile ->
-                builder.withDynamicThreshold(percentileTracker, slowQueryLatencyThresholdPercentile)
-            )
-        );
-
-        constantThreshold.ifPresent(builder::withConstantThreshold);
-        constantThreshold.ifPresent(builder::withConstantThreshold);
-        maxLoggedParameters.ifPresent(builder::withMaxLoggedParameters);
-        maxParameterValueLength.ifPresent(builder::withMaxParameterValueLength);
-        maxQueryStringLength.ifPresent(builder::withMaxQueryStringLength);
-
-        return builder.build();
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
index 96d6fe1..ebfd70b 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/SessionWithInitializedTablesFactory.java
@@ -24,25 +24,21 @@ import javax.inject.Inject;
 import javax.inject.Provider;
 import javax.inject.Singleton;
 
-import org.apache.commons.configuration.ConfigurationException;
 import org.apache.james.backends.cassandra.components.CassandraModule;
+import org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
 
 import com.datastax.driver.core.Cluster;
 import com.datastax.driver.core.Session;
 
 @Singleton
 public class SessionWithInitializedTablesFactory implements Provider<Session> {
-    
-    private static final String DEFAULT_KEYSPACE_NAME = "apache_james";
-
     private final CassandraModule module;
     private final Session session;
 
     @Inject
-    public SessionWithInitializedTablesFactory(CassandraSessionConfiguration configuration, Cluster cluster, CassandraModule module) throws ConfigurationException {
-        String keyspace = configuration.getConfiguration().getString("cassandra.keyspace", DEFAULT_KEYSPACE_NAME);
+    public SessionWithInitializedTablesFactory(ClusterConfiguration clusterConfiguration, Cluster cluster, CassandraModule module) {
         this.module = module;
-        this.session = createSession(cluster, keyspace);
+        this.session = createSession(cluster, clusterConfiguration.getKeyspace());
     }
 
     public Session createSession(Cluster cluster, String keyspace) {
@@ -69,5 +65,4 @@ public class SessionWithInitializedTablesFactory implements Provider<Session> {
         session.close();
     }
 
-
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConfiguration.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConfiguration.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConfiguration.java
new file mode 100644
index 0000000..bf7e837
--- /dev/null
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConfiguration.java
@@ -0,0 +1,384 @@
+/****************************************************************
+ * 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.cassandra.init.configuration;
+
+import static java.lang.Math.toIntExact;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class CassandraConfiguration {
+    public static final int DEFAULT_MESSAGE_CHUNK_SIZE_ON_READ = 100;
+    public static final int DEFAULT_EXPUNGE_BATCH_SIZE = 100;
+    public static final int DEFAULT_UPDATE_FLAGS_BATCH_SIZE = 20;
+    public static final int DEFAULT_FLAGS_UPDATE_MESSAGE_MAX_RETRY = 1000;
+    public static final int DEFAULT_FLAGS_UPDATE_MESSAGE_ID_MAX_RETRY = 1000;
+    public static final int DEFAULT_MODSEQ_MAX_RETRY = 100000;
+    public static final int DEFAULT_UID_MAX_RETRY = 100000;
+    public static final int DEFAULT_ACL_MAX_RETRY = 1000;
+    public static final int DEFAULT_FETCH_NEXT_PAGE_ADVANCE_IN_ROW = 100;
+    public static final int DEFAULT_BLOB_PART_SIZE = 100 * 1024;
+    public static final int DEFAULT_ATTACHMENT_V2_MIGRATION_READ_TIMEOUT = toIntExact(TimeUnit.HOURS.toMillis(1));
+    public static final int DEFAULT_MESSAGE_ATTACHMENT_ID_MIGRATION_READ_TIMEOUT = toIntExact(TimeUnit.HOURS.toMillis(1));
+
+
+    private static final String MAILBOX_MAX_RETRY_ACL = "mailbox.max.retry.acl";
+    private static final String MAILBOX_MAX_RETRY_MODSEQ = "mailbox.max.retry.modseq";
+    private static final String MAILBOX_MAX_RETRY_UID = "mailbox.max.retry.uid";
+    private static final String MAILBOX_MAX_RETRY_MESSAGE_FLAGS_UPDATE = "mailbox.max.retry.message.flags.update";
+    private static final String MAILBOX_MAX_RETRY_MESSAGE_ID_FLAGS_UPDATE = "mailbox.max.retry.message.id.flags.update";
+    private static final String FETCH_ADVANCE_ROW_COUNT = "fetch.advance.row.count";
+    private static final String CHUNK_SIZE_FLAGS_UPDATE = "chunk.size.flags.update";
+    private static final String CHUNK_SIZE_MESSAGE_READ = "chunk.size.message.read";
+    private static final String CHUNK_SIZE_EXPUNGE = "chunk.size.expunge";
+    private static final String BLOB_PART_SIZE = "mailbox.blob.part.size";
+    private static final String ATTACHMENT_V2_MIGRATION_READ_TIMEOUT = "attachment.v2.migration.read.timeout";
+    private static final String MESSAGE_ATTACHMENTID_READ_TIMEOUT = "message.attachmentids.read.timeout";
+
+    public static final CassandraConfiguration DEFAULT_CONFIGURATION = builder().build();
+
+    public static class Builder {
+        private Optional<Integer> messageReadChunkSize = Optional.empty();
+        private Optional<Integer> expungeChunkSize = Optional.empty();
+        private Optional<Integer> flagsUpdateChunkSize = Optional.empty();
+        private Optional<Integer> flagsUpdateMessageIdMaxRetry = Optional.empty();
+        private Optional<Integer> flagsUpdateMessageMaxRetry = Optional.empty();
+        private Optional<Integer> modSeqMaxRetry = Optional.empty();
+        private Optional<Integer> uidMaxRetry = Optional.empty();
+        private Optional<Integer> aclMaxRetry = Optional.empty();
+        private Optional<Integer> fetchNextPageInAdvanceRow = Optional.empty();
+        private Optional<Integer> blobPartSize = Optional.empty();
+        private Optional<Integer> attachmentV2MigrationReadTimeout = Optional.empty();
+        private Optional<Integer> messageAttachmentIdsReadTimeout = Optional.empty();
+
+        public Builder messageReadChunkSize(int value) {
+            Preconditions.checkArgument(value > 0, "messageReadChunkSize needs to be strictly positive");
+            this.messageReadChunkSize = Optional.of(value);
+            return this;
+        }
+
+        public Builder expungeChunkSize(int value) {
+            Preconditions.checkArgument(value > 0, "expungeChunkSize needs to be strictly positive");
+            this.expungeChunkSize = Optional.of(value);
+            return this;
+        }
+
+        public Builder flagsUpdateChunkSize(int value) {
+            Preconditions.checkArgument(value > 0, "flagsUpdateChunkSize needs to be strictly positive");
+            this.flagsUpdateChunkSize = Optional.of(value);
+            return this;
+        }
+
+        public Builder flagsUpdateMessageIdMaxRetry(int value) {
+            Preconditions.checkArgument(value > 0, "flagsUpdateMessageIdMaxRetry needs to be strictly positive");
+            this.flagsUpdateMessageIdMaxRetry = Optional.of(value);
+            return this;
+        }
+
+        public Builder flagsUpdateMessageMaxRetry(int value) {
+            Preconditions.checkArgument(value > 0, "flagsUpdateMessageMaxRetry needs to be strictly positive");
+            this.flagsUpdateMessageMaxRetry = Optional.of(value);
+            return this;
+        }
+
+        public Builder modSeqMaxRetry(int value) {
+            Preconditions.checkArgument(value > 0, "modSeqMaxRetry needs to be strictly positive");
+            this.modSeqMaxRetry = Optional.of(value);
+            return this;
+        }
+
+        public Builder uidMaxRetry(int value) {
+            Preconditions.checkArgument(value > 0, "uidMaxRetry needs to be strictly positive");
+            this.uidMaxRetry = Optional.of(value);
+            return this;
+        }
+
+        public Builder aclMaxRetry(int value) {
+            Preconditions.checkArgument(value > 0, "aclMaxRetry needs to be strictly positive");
+            this.aclMaxRetry = Optional.of(value);
+            return this;
+        }
+
+        public Builder fetchNextPageInAdvanceRow(int value) {
+            Preconditions.checkArgument(value > 0, "fetchNextPageInAdvanceRow needs to be strictly positive");
+            this.fetchNextPageInAdvanceRow = Optional.of(value);
+            return this;
+        }
+
+        public Builder blobPartSize(int value) {
+            Preconditions.checkArgument(value > 0, "blobPartSize needs to be strictly positive");
+            this.blobPartSize = Optional.of(value);
+            return this;
+        }
+
+        public Builder attachmentV2MigrationReadTimeout(int value) {
+            Preconditions.checkArgument(value > 0, "attachmentV2MigrationReadTimeout needs to be strictly positive");
+            this.attachmentV2MigrationReadTimeout = Optional.of(value);
+            return this;
+        }
+
+        public Builder messageAttachmentIdsReadTimeout(int value) {
+            Preconditions.checkArgument(value > 0, "messageAttachmentIdsReadTimeout needs to be strictly positive");
+            this.messageAttachmentIdsReadTimeout = Optional.of(value);
+            return this;
+        }
+
+        public Builder messageReadChunkSize(Optional<Integer> value) {
+            value.ifPresent(this::messageReadChunkSize);
+            return this;
+        }
+
+        public Builder expungeChunkSize(Optional<Integer> value) {
+            value.ifPresent(this::expungeChunkSize);
+            return this;
+        }
+
+        public Builder flagsUpdateChunkSize(Optional<Integer> value) {
+            value.ifPresent(this::flagsUpdateChunkSize);
+            return this;
+        }
+
+        public Builder flagsUpdateMessageIdMaxRetry(Optional<Integer> value) {
+            value.ifPresent(this::flagsUpdateMessageIdMaxRetry);
+            return this;
+        }
+
+        public Builder flagsUpdateMessageMaxRetry(Optional<Integer> value) {
+            value.ifPresent(this::flagsUpdateMessageMaxRetry);
+            return this;
+        }
+
+        public Builder modSeqMaxRetry(Optional<Integer> value) {
+            value.ifPresent(this::modSeqMaxRetry);
+            return this;
+        }
+
+        public Builder uidMaxRetry(Optional<Integer> value) {
+            value.ifPresent(this::uidMaxRetry);
+            return this;
+        }
+
+        public Builder aclMaxRetry(Optional<Integer> value) {
+            value.ifPresent(this::aclMaxRetry);
+            return this;
+        }
+
+        public Builder fetchNextPageInAdvanceRow(Optional<Integer> value) {
+            value.ifPresent(this::fetchNextPageInAdvanceRow);
+            return this;
+        }
+
+        public Builder blobPartSize(Optional<Integer> value) {
+            value.ifPresent(this::blobPartSize);
+            return this;
+        }
+
+        public Builder attachmentV2MigrationReadTimeout(Optional<Integer> value) {
+            value.ifPresent(this::attachmentV2MigrationReadTimeout);
+            return this;
+        }
+
+        public Builder messageAttachmentIdsReadTimeout(Optional<Integer> value) {
+            value.ifPresent(this::messageAttachmentIdsReadTimeout);
+            return this;
+        }
+
+        public CassandraConfiguration build() {
+            return new CassandraConfiguration(aclMaxRetry.orElse(DEFAULT_ACL_MAX_RETRY),
+                messageReadChunkSize.orElse(DEFAULT_MESSAGE_CHUNK_SIZE_ON_READ),
+                expungeChunkSize.orElse(DEFAULT_EXPUNGE_BATCH_SIZE),
+                flagsUpdateChunkSize.orElse(DEFAULT_UPDATE_FLAGS_BATCH_SIZE),
+                flagsUpdateMessageIdMaxRetry.orElse(DEFAULT_FLAGS_UPDATE_MESSAGE_ID_MAX_RETRY),
+                flagsUpdateMessageMaxRetry.orElse(DEFAULT_FLAGS_UPDATE_MESSAGE_MAX_RETRY),
+                modSeqMaxRetry.orElse(DEFAULT_MODSEQ_MAX_RETRY),
+                uidMaxRetry.orElse(DEFAULT_UID_MAX_RETRY),
+                fetchNextPageInAdvanceRow.orElse(DEFAULT_FETCH_NEXT_PAGE_ADVANCE_IN_ROW),
+                blobPartSize.orElse(DEFAULT_BLOB_PART_SIZE),
+                attachmentV2MigrationReadTimeout.orElse(DEFAULT_ATTACHMENT_V2_MIGRATION_READ_TIMEOUT),
+                messageAttachmentIdsReadTimeout.orElse(DEFAULT_MESSAGE_ATTACHMENT_ID_MIGRATION_READ_TIMEOUT));
+        }
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static CassandraConfiguration from(PropertiesConfiguration propertiesConfiguration) {
+        return builder()
+            .aclMaxRetry(Optional.ofNullable(
+                propertiesConfiguration.getInteger(MAILBOX_MAX_RETRY_ACL, null)))
+            .modSeqMaxRetry(Optional.ofNullable(
+                propertiesConfiguration.getInteger(MAILBOX_MAX_RETRY_MODSEQ, null)))
+            .uidMaxRetry(Optional.ofNullable(
+                propertiesConfiguration.getInteger(MAILBOX_MAX_RETRY_UID, null)))
+            .flagsUpdateMessageMaxRetry(Optional.ofNullable(
+                propertiesConfiguration.getInteger(MAILBOX_MAX_RETRY_MESSAGE_FLAGS_UPDATE, null)))
+            .flagsUpdateMessageIdMaxRetry(Optional.ofNullable(
+                propertiesConfiguration.getInteger(MAILBOX_MAX_RETRY_MESSAGE_ID_FLAGS_UPDATE, null)))
+            .fetchNextPageInAdvanceRow(Optional.ofNullable(
+                propertiesConfiguration.getInteger(FETCH_ADVANCE_ROW_COUNT, null)))
+            .flagsUpdateChunkSize(Optional.ofNullable(
+                propertiesConfiguration.getInteger(CHUNK_SIZE_FLAGS_UPDATE, null)))
+            .messageReadChunkSize(Optional.ofNullable(
+                propertiesConfiguration.getInteger(CHUNK_SIZE_MESSAGE_READ, null)))
+            .expungeChunkSize(Optional.ofNullable(
+                propertiesConfiguration.getInteger(CHUNK_SIZE_EXPUNGE, null)))
+            .blobPartSize(Optional.ofNullable(
+                propertiesConfiguration.getInteger(BLOB_PART_SIZE, null)))
+            .attachmentV2MigrationReadTimeout(Optional.ofNullable(
+                propertiesConfiguration.getInteger(ATTACHMENT_V2_MIGRATION_READ_TIMEOUT, null)))
+            .messageAttachmentIdsReadTimeout(Optional.ofNullable(
+                propertiesConfiguration.getInteger(MESSAGE_ATTACHMENTID_READ_TIMEOUT, null)))
+            .build();
+    }
+
+    private final int messageReadChunkSize;
+    private final int expungeChunkSize;
+    private final int flagsUpdateChunkSize;
+    private final int flagsUpdateMessageIdMaxRetry;
+    private final int flagsUpdateMessageMaxRetry;
+    private final int modSeqMaxRetry;
+    private final int uidMaxRetry;
+    private final int aclMaxRetry;
+    private final int fetchNextPageInAdvanceRow;
+    private final int blobPartSize;
+    private final int attachmentV2MigrationReadTimeout;
+    private final int messageAttachmentIdsReadTimeout;
+
+    @VisibleForTesting
+    CassandraConfiguration(int aclMaxRetry, int messageReadChunkSize, int expungeChunkSize,
+                           int flagsUpdateChunkSize, int flagsUpdateMessageIdMaxRetry, int flagsUpdateMessageMaxRetry,
+                           int modSeqMaxRetry, int uidMaxRetry, int fetchNextPageInAdvanceRow,
+                           int blobPartSize, final int attachmentV2MigrationReadTimeout, int messageAttachmentIdsReadTimeout) {
+        this.aclMaxRetry = aclMaxRetry;
+        this.messageReadChunkSize = messageReadChunkSize;
+        this.expungeChunkSize = expungeChunkSize;
+        this.flagsUpdateMessageIdMaxRetry = flagsUpdateMessageIdMaxRetry;
+        this.flagsUpdateMessageMaxRetry = flagsUpdateMessageMaxRetry;
+        this.modSeqMaxRetry = modSeqMaxRetry;
+        this.uidMaxRetry = uidMaxRetry;
+        this.fetchNextPageInAdvanceRow = fetchNextPageInAdvanceRow;
+        this.flagsUpdateChunkSize = flagsUpdateChunkSize;
+        this.blobPartSize = blobPartSize;
+        this.attachmentV2MigrationReadTimeout = attachmentV2MigrationReadTimeout;
+        this.messageAttachmentIdsReadTimeout = messageAttachmentIdsReadTimeout;
+    }
+
+    public int getBlobPartSize() {
+        return blobPartSize;
+    }
+
+    public int getFlagsUpdateChunkSize() {
+        return flagsUpdateChunkSize;
+    }
+
+    public int getAclMaxRetry() {
+        return aclMaxRetry;
+    }
+
+    public int getMessageReadChunkSize() {
+        return messageReadChunkSize;
+    }
+
+    public int getExpungeChunkSize() {
+        return expungeChunkSize;
+    }
+
+    public int getFlagsUpdateMessageIdMaxRetry() {
+        return flagsUpdateMessageIdMaxRetry;
+    }
+
+    public int getFlagsUpdateMessageMaxRetry() {
+        return flagsUpdateMessageMaxRetry;
+    }
+
+    public int getModSeqMaxRetry() {
+        return modSeqMaxRetry;
+    }
+
+    public int getUidMaxRetry() {
+        return uidMaxRetry;
+    }
+
+    public int getFetchNextPageInAdvanceRow() {
+        return fetchNextPageInAdvanceRow;
+    }
+
+    public int getAttachmentV2MigrationReadTimeout() {
+        return attachmentV2MigrationReadTimeout;
+    }
+
+    public int getMessageAttachmentIdsReadTimeout() {
+        return messageAttachmentIdsReadTimeout;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof CassandraConfiguration) {
+            CassandraConfiguration that = (CassandraConfiguration) o;
+
+            return Objects.equals(this.aclMaxRetry, that.aclMaxRetry)
+                && Objects.equals(this.messageReadChunkSize, that.messageReadChunkSize)
+                && Objects.equals(this.expungeChunkSize, that.expungeChunkSize)
+                && Objects.equals(this.flagsUpdateMessageIdMaxRetry, that.flagsUpdateMessageIdMaxRetry)
+                && Objects.equals(this.flagsUpdateMessageMaxRetry, that.flagsUpdateMessageMaxRetry)
+                && Objects.equals(this.modSeqMaxRetry, that.modSeqMaxRetry)
+                && Objects.equals(this.uidMaxRetry, that.uidMaxRetry)
+                && Objects.equals(this.flagsUpdateChunkSize, that.flagsUpdateChunkSize)
+                && Objects.equals(this.fetchNextPageInAdvanceRow, that.fetchNextPageInAdvanceRow)
+                && Objects.equals(this.blobPartSize, that.blobPartSize)
+                && Objects.equals(this.attachmentV2MigrationReadTimeout, that.attachmentV2MigrationReadTimeout)
+                && Objects.equals(this.messageAttachmentIdsReadTimeout, that.messageAttachmentIdsReadTimeout);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(aclMaxRetry, messageReadChunkSize, expungeChunkSize, flagsUpdateMessageIdMaxRetry,
+            flagsUpdateMessageMaxRetry, modSeqMaxRetry, uidMaxRetry, fetchNextPageInAdvanceRow, flagsUpdateChunkSize,
+            blobPartSize, attachmentV2MigrationReadTimeout, messageAttachmentIdsReadTimeout);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("aclMaxRetry", aclMaxRetry)
+            .add("messageReadChunkSize", messageReadChunkSize)
+            .add("expungeChunkSize", expungeChunkSize)
+            .add("flagsUpdateMessageIdMaxRetry", flagsUpdateMessageIdMaxRetry)
+            .add("flagsUpdateMessageMaxRetry", flagsUpdateMessageMaxRetry)
+            .add("modSeqMaxRetry", modSeqMaxRetry)
+            .add("fetchNextPageInAdvanceRow", fetchNextPageInAdvanceRow)
+            .add("flagsUpdateChunkSize", flagsUpdateChunkSize)
+            .add("uidMaxRetry", uidMaxRetry)
+            .add("blobPartSize", blobPartSize)
+            .add("attachmentV2MigrationReadTimeout", attachmentV2MigrationReadTimeout)
+            .add("messageAttachmentIdsReadTimeout", messageAttachmentIdsReadTimeout)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
new file mode 100644
index 0000000..4b15a5f
--- /dev/null
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/ClusterConfiguration.java
@@ -0,0 +1,311 @@
+/****************************************************************
+ * 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.cassandra.init.configuration;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.james.backends.cassandra.init.ClusterBuilder;
+import org.apache.james.util.Host;
+
+import com.datastax.driver.core.HostDistance;
+import com.datastax.driver.core.PoolingOptions;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableList;
+
+public class ClusterConfiguration {
+
+    public static class Builder {
+        private ImmutableList.Builder<Host> hosts;
+        private Optional<String> keyspace;
+        private Optional<Integer> replicationFactor;
+        private Optional<Integer> minDelay;
+        private Optional<Integer> maxRetry;
+        private Optional<QueryLoggerConfiguration> queryLoggerConfiguration;
+        private Optional<PoolingOptions> poolingOptions;
+        private Optional<Integer> readTimeoutMillis;
+        private Optional<Integer> connectTimeoutMillis;
+
+        public Builder() {
+            hosts = ImmutableList.builder();
+            keyspace = Optional.empty();
+            replicationFactor = Optional.empty();
+            minDelay = Optional.empty();
+            maxRetry = Optional.empty();
+            queryLoggerConfiguration = Optional.empty();
+            poolingOptions = Optional.empty();
+            readTimeoutMillis = Optional.empty();
+            connectTimeoutMillis = Optional.empty();
+        }
+
+        public Builder host(Host host) {
+            this.hosts.add(host);
+            return this;
+        }
+
+        public Builder hosts(Collection<Host> hosts) {
+            this.hosts.addAll(hosts);
+            return this;
+        }
+
+        public Builder hosts(Host... hosts) {
+            this.hosts.addAll(Arrays.asList(hosts));
+            return this;
+        }
+
+        public Builder keyspace(Optional<String> keyspace) {
+            this.keyspace = keyspace;
+            return this;
+        }
+
+        public Builder keyspace(String keyspace) {
+            return keyspace(Optional.of(keyspace));
+        }
+
+        public Builder replicationFactor(Optional<Integer> replicationFactor) {
+            this.replicationFactor = replicationFactor;
+            return this;
+        }
+
+        public Builder replicationFactor(int replicationFactor) {
+            return replicationFactor(Optional.of(replicationFactor));
+        }
+
+        public Builder minDelay(Optional<Integer> minDelay) {
+            this.minDelay = minDelay;
+            return this;
+        }
+
+        public Builder minDelay(int minDelay) {
+            return minDelay(Optional.of(minDelay));
+        }
+
+        public Builder maxRetry(Optional<Integer> maxRetry) {
+            this.maxRetry = maxRetry;
+            return this;
+        }
+
+        public Builder maxRetry(int maxRetry) {
+            return maxRetry(Optional.of(maxRetry));
+        }
+
+        public Builder queryLoggerConfiguration(QueryLoggerConfiguration queryLoggerConfiguration) {
+            this.queryLoggerConfiguration = Optional.of(queryLoggerConfiguration);
+            return this;
+        }
+
+        public Builder poolingOptions(Optional<PoolingOptions> poolingOptions) {
+            this.poolingOptions = poolingOptions;
+            return this;
+        }
+
+        public Builder poolingOptions(PoolingOptions poolingOptions) {
+            return poolingOptions(Optional.of(poolingOptions));
+        }
+
+        public Builder readTimeoutMillis(Optional<Integer> readTimeoutMillis) {
+            this.readTimeoutMillis = readTimeoutMillis;
+            return this;
+        }
+
+        public Builder readTimeoutMillis(int readTimeoutMillis) {
+            return readTimeoutMillis(Optional.of(readTimeoutMillis));
+        }
+
+        public Builder connectTimeoutMillis(Optional<Integer> connectTimeoutMillis) {
+            this.connectTimeoutMillis = connectTimeoutMillis;
+            return this;
+        }
+
+        public Builder connectTimeoutMillis(int connectTimeoutMillis) {
+            return connectTimeoutMillis(Optional.of(connectTimeoutMillis));
+        }
+
+        public ClusterConfiguration build() {
+            return new ClusterConfiguration(
+                hosts.build(),
+                keyspace.orElse(DEFAULT_KEYSPACE),
+                replicationFactor.orElse(DEFAULT_REPLICATION_FACTOR),
+                minDelay.orElse(DEFAULT_CONNECTION_MIN_DELAY),
+                maxRetry.orElse(DEFAULT_CONNECTION_MAX_RETRIES),
+                queryLoggerConfiguration.orElse(QueryLoggerConfiguration.DEFAULT),
+                poolingOptions,
+                readTimeoutMillis.orElse(DEFAULT_READ_TIMEOUT_MILLIS),
+                connectTimeoutMillis.orElse(DEFAULT_CONNECT_TIMEOUT_MILLIS));
+        }
+    }
+
+    private static final String CASSANDRA_NODES = "cassandra.nodes";
+    public static final String CASSANDRA_KEYSPACE = "cassandra.keyspace";
+    public static final String REPLICATION_FACTOR = "cassandra.replication.factor";
+    public static final String READ_TIMEOUT_MILLIS = "cassandra.readTimeoutMillis";
+    public static final String CONNECT_TIMEOUT_MILLIS = "cassandra.connectTimeoutMillis";
+    public static final String CONNECTION_MAX_RETRY = "cassandra.retryConnection.maxRetries";
+    public static final String CONNECTION_RETRY_MIN_DELAY = "cassandra.retryConnection.minDelay";
+
+    private static final String DEFAULT_KEYSPACE = "apache_james";
+    private static final int DEFAULT_REPLICATION_FACTOR = 1;
+    private static final int DEFAULT_CONNECTION_MAX_RETRIES = 10;
+    private static final int DEFAULT_CONNECTION_MIN_DELAY = 5000;
+    private static final int DEFAULT_READ_TIMEOUT_MILLIS = 5000;
+    private static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 5000;
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static ClusterConfiguration from(PropertiesConfiguration configuration) {
+        return ClusterConfiguration.builder()
+            .hosts(listCassandraServers(configuration))
+            .keyspace(Optional.ofNullable(configuration.getString(CASSANDRA_KEYSPACE, null)))
+            .replicationFactor(Optional.ofNullable(configuration.getInteger(REPLICATION_FACTOR, null)))
+            .minDelay(Optional.ofNullable(configuration.getInteger(CONNECTION_RETRY_MIN_DELAY, null)))
+            .maxRetry(Optional.ofNullable(configuration.getInteger(CONNECTION_MAX_RETRY, null)))
+            .queryLoggerConfiguration(QueryLoggerConfiguration.from(configuration))
+            .poolingOptions(readPoolingOptions(configuration))
+            .readTimeoutMillis(Optional.ofNullable(configuration.getInteger(READ_TIMEOUT_MILLIS, null)))
+            .connectTimeoutMillis(Optional.ofNullable(configuration.getInteger(CONNECT_TIMEOUT_MILLIS, null)))
+            .build();
+    }
+
+    private static List<Host> listCassandraServers(PropertiesConfiguration configuration) {
+        String[] ipAndPorts = configuration.getStringArray(CASSANDRA_NODES);
+
+        return Arrays.stream(ipAndPorts)
+            .map(string -> Host.parseConfString(string, ClusterBuilder.DEFAULT_CASSANDRA_PORT))
+            .collect(Guavate.toImmutableList());
+    }
+
+    private static Optional<PoolingOptions> readPoolingOptions(PropertiesConfiguration configuration) {
+        Optional<Integer> maxConnections = Optional.ofNullable(configuration.getInteger("cassandra.pooling.local.max.connections", null));
+        Optional<Integer> maxRequests = Optional.ofNullable(configuration.getInteger("cassandra.pooling.local.max.requests", null));
+        Optional<Integer> poolingTimeout = Optional.ofNullable(configuration.getInteger("cassandra.pooling.timeout", null));
+        Optional<Integer> heartbeatTimeout = Optional.ofNullable(configuration.getInteger("cassandra.pooling.heartbeat.timeout", null));
+
+        if (!maxConnections.isPresent()
+            && !maxRequests.isPresent()
+            && !poolingTimeout.isPresent()
+            && !heartbeatTimeout.isPresent()) {
+            return Optional.empty();
+        }
+        PoolingOptions result = new PoolingOptions();
+
+        maxConnections.ifPresent(value -> {
+            result.setMaxConnectionsPerHost(HostDistance.LOCAL, value);
+            result.setMaxConnectionsPerHost(HostDistance.REMOTE, value);
+        });
+        maxRequests.ifPresent(value -> {
+            result.setMaxRequestsPerConnection(HostDistance.LOCAL, value);
+            result.setMaxRequestsPerConnection(HostDistance.REMOTE, value);
+        });
+        poolingTimeout.ifPresent(result::setPoolTimeoutMillis);
+        heartbeatTimeout.ifPresent(result::setHeartbeatIntervalSeconds);
+
+        return Optional.of(result);
+    }
+
+    private final List<Host> hosts;
+    private final String keyspace;
+    private final int replicationFactor;
+    private final int minDelay;
+    private final int maxRetry;
+    private final QueryLoggerConfiguration queryLoggerConfiguration;
+    private final Optional<PoolingOptions> poolingOptions;
+    private final int readTimeoutMillis;
+    private final int connectTimeoutMillis;
+
+    public ClusterConfiguration(List<Host> hosts, String keyspace, int replicationFactor, int minDelay, int maxRetry,
+                                QueryLoggerConfiguration queryLoggerConfiguration, Optional<PoolingOptions> poolingOptions,
+                                int readTimeoutMillis, int connectTimeoutMillis) {
+        this.hosts = hosts;
+        this.keyspace = keyspace;
+        this.replicationFactor = replicationFactor;
+        this.minDelay = minDelay;
+        this.maxRetry = maxRetry;
+        this.queryLoggerConfiguration = queryLoggerConfiguration;
+        this.poolingOptions = poolingOptions;
+        this.readTimeoutMillis = readTimeoutMillis;
+        this.connectTimeoutMillis = connectTimeoutMillis;
+    }
+
+    public List<Host> getHosts() {
+        return hosts;
+    }
+
+    public String getKeyspace() {
+        return keyspace;
+    }
+
+    public int getReplicationFactor() {
+        return replicationFactor;
+    }
+
+    public int getMinDelay() {
+        return minDelay;
+    }
+
+    public int getMaxRetry() {
+        return maxRetry;
+    }
+
+    public QueryLoggerConfiguration getQueryLoggerConfiguration() {
+        return queryLoggerConfiguration;
+    }
+
+    public Optional<PoolingOptions> getPoolingOptions() {
+        return poolingOptions;
+    }
+
+    public int getReadTimeoutMillis() {
+        return readTimeoutMillis;
+    }
+
+    public int getConnectTimeoutMillis() {
+        return connectTimeoutMillis;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof ClusterConfiguration) {
+            ClusterConfiguration that = (ClusterConfiguration) o;
+
+            return Objects.equals(this.minDelay, that.minDelay)
+                && Objects.equals(this.maxRetry, that.maxRetry)
+                && Objects.equals(this.hosts, that.hosts)
+                && Objects.equals(this.keyspace, that.keyspace)
+                && Objects.equals(this.replicationFactor, that.replicationFactor)
+                && Objects.equals(this.queryLoggerConfiguration, that.queryLoggerConfiguration)
+                && Objects.equals(this.poolingOptions, that.poolingOptions)
+                && Objects.equals(this.readTimeoutMillis, that.readTimeoutMillis)
+                && Objects.equals(this.connectTimeoutMillis, that.connectTimeoutMillis);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(hosts, keyspace, replicationFactor, minDelay, maxRetry, queryLoggerConfiguration, poolingOptions,
+            readTimeoutMillis, connectTimeoutMillis);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/QueryLoggerConfiguration.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/QueryLoggerConfiguration.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/QueryLoggerConfiguration.java
new file mode 100644
index 0000000..2ce7bf4
--- /dev/null
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/QueryLoggerConfiguration.java
@@ -0,0 +1,191 @@
+/****************************************************************
+ * 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.cassandra.init.configuration;
+
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+
+import com.datastax.driver.core.PerHostPercentileTracker;
+import com.datastax.driver.core.QueryLogger;
+import com.google.common.base.Preconditions;
+
+public class QueryLoggerConfiguration {
+
+    public static class Builder {
+        private Optional<Long> constantThreshold;
+        private Optional<PerHostPercentileTracker> percentileTracker;
+        private Optional<Double> slowQueryLatencyThresholdPercentile;
+        private Optional<Integer> maxLoggedParameters;
+        private Optional<Integer> maxParameterValueLength;
+        private Optional<Integer> maxQueryStringLength;
+
+        private Builder() {
+            constantThreshold = Optional.empty();
+            percentileTracker = Optional.empty();
+            slowQueryLatencyThresholdPercentile = Optional.empty();
+            maxLoggedParameters = Optional.empty();
+            maxParameterValueLength = Optional.empty();
+            maxQueryStringLength = Optional.empty();
+        }
+
+        public Builder withConstantThreshold(long constantThreshold) {
+            this.constantThreshold = Optional.of(constantThreshold);
+
+            return this;
+        }
+
+        public Builder withDynamicThreshold(PerHostPercentileTracker percentileTracker,
+                                            double slowQueryLatencyThresholdPercentile) {
+            this.percentileTracker = Optional.of(percentileTracker);
+            this.slowQueryLatencyThresholdPercentile = Optional.of(slowQueryLatencyThresholdPercentile);
+
+            return this;
+        }
+
+        public Builder withMaxLoggedParameters(int maxLoggedParameters) {
+            this.maxLoggedParameters = Optional.of(maxLoggedParameters);
+
+            return this;
+        }
+
+        public Builder withMaxParameterValueLength(int maxParameterValueLength) {
+            this.maxParameterValueLength = Optional.of(maxParameterValueLength);
+
+            return this;
+        }
+
+        public Builder withMaxQueryStringLength(int maxQueryStringLength) {
+            this.maxQueryStringLength = Optional.of(maxQueryStringLength);
+
+            return this;
+        }
+
+        public QueryLoggerConfiguration build() {
+            Preconditions.checkState(!(constantThreshold.isPresent() && percentileTracker.isPresent()),
+                "You can not use slowQueryLatencyTheresholdMillis and percentileTracker at the same time");
+
+            return new QueryLoggerConfiguration(
+                constantThreshold,
+                percentileTracker,
+                slowQueryLatencyThresholdPercentile,
+                maxLoggedParameters,
+                maxParameterValueLength,
+                maxQueryStringLength
+            );
+        }
+    }
+
+    private static final long CASSANDRA_HIGHEST_TRACKABLE_LATENCY_MILLIS = TimeUnit.SECONDS.toMillis(10);
+
+    public static final QueryLoggerConfiguration DEFAULT = QueryLoggerConfiguration.builder()
+        .withDynamicThreshold(PerHostPercentileTracker
+            .builder(CASSANDRA_HIGHEST_TRACKABLE_LATENCY_MILLIS)
+            .build(),
+            QueryLogger.DEFAULT_SLOW_QUERY_THRESHOLD_PERCENTILE)
+        .build();
+
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static QueryLoggerConfiguration from(PropertiesConfiguration configuration) {
+        QueryLoggerConfiguration.Builder builder = QueryLoggerConfiguration.builder();
+
+        Optional<Long> constantThreshold = getOptionalIntegerFromConf(configuration, "cassandra.query.logger.constant.threshold")
+            .map(Long::valueOf);
+
+        constantThreshold.ifPresent(builder::withConstantThreshold);
+
+        getOptionalIntegerFromConf(configuration, "cassandra.query.logger.max.logged.parameters")
+            .ifPresent(builder::withMaxLoggedParameters);
+
+        getOptionalIntegerFromConf(configuration, "cassandra.query.logger.max.query.string.length")
+            .ifPresent(builder::withMaxQueryStringLength);
+
+        getOptionalIntegerFromConf(configuration, "cassandra.query.logger.max.parameter.value.length")
+            .ifPresent(builder::withMaxParameterValueLength);
+
+        Optional<Double> percentileLatencyConf = getOptionalDoubleFromConf(configuration, "cassandra.query.slow.query.latency.threshold.percentile");
+
+        if (!percentileLatencyConf.isPresent() && !constantThreshold.isPresent()) {
+            percentileLatencyConf = Optional.of(QueryLogger.DEFAULT_SLOW_QUERY_THRESHOLD_PERCENTILE);
+        }
+
+        percentileLatencyConf.ifPresent(slowQueryLatencyThresholdPercentile -> {
+            PerHostPercentileTracker tracker = PerHostPercentileTracker
+                .builder(CASSANDRA_HIGHEST_TRACKABLE_LATENCY_MILLIS)
+                .build();
+
+            builder.withDynamicThreshold(tracker, slowQueryLatencyThresholdPercentile);
+        });
+
+        return builder.build();
+    }
+
+    private static Optional<Integer> getOptionalIntegerFromConf(PropertiesConfiguration configuration, String key) {
+        return Optional.ofNullable(configuration.getInteger(key, null));
+    }
+
+    private static Optional<Double> getOptionalDoubleFromConf(PropertiesConfiguration configuration, String key) {
+        return Optional.ofNullable(configuration.getDouble(key, null));
+    }
+
+    private final Optional<Long> constantThreshold;
+    private final Optional<PerHostPercentileTracker> percentileTracker;
+    private final Optional<Double> slowQueryLatencyThresholdPercentile;
+    private final Optional<Integer> maxLoggedParameters;
+    private final Optional<Integer> maxParameterValueLength;
+    private final Optional<Integer> maxQueryStringLength;
+
+    private QueryLoggerConfiguration(Optional<Long> constantThreshold,
+                                     Optional<PerHostPercentileTracker> percentileTracker,
+                                     Optional<Double> slowQueryLatencyThresholdPercentile,
+                                     Optional<Integer> maxLoggedParameters,
+                                     Optional<Integer> maxParameterValueLength,
+                                     Optional<Integer> maxQueryStringLength) {
+        this.constantThreshold = constantThreshold;
+        this.percentileTracker = percentileTracker;
+        this.slowQueryLatencyThresholdPercentile = slowQueryLatencyThresholdPercentile;
+        this.maxLoggedParameters = maxLoggedParameters;
+        this.maxParameterValueLength = maxParameterValueLength;
+        this.maxQueryStringLength = maxQueryStringLength;
+    }
+
+    public QueryLogger getQueryLogger() {
+        QueryLogger.Builder builder = QueryLogger.builder();
+
+        percentileTracker.map(percentileTracker ->
+            slowQueryLatencyThresholdPercentile.map(slowQueryLatencyThresholdPercentile ->
+                builder.withDynamicThreshold(percentileTracker, slowQueryLatencyThresholdPercentile)
+            )
+        );
+
+        constantThreshold.ifPresent(builder::withConstantThreshold);
+        constantThreshold.ifPresent(builder::withConstantThreshold);
+        maxLoggedParameters.ifPresent(builder::withMaxLoggedParameters);
+        maxParameterValueLength.ifPresent(builder::withMaxParameterValueLength);
+        maxQueryStringLength.ifPresent(builder::withMaxQueryStringLength);
+
+        return builder.build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraUtils.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraUtils.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraUtils.java
index 5d6dc33..fa749e6 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraUtils.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/utils/CassandraUtils.java
@@ -24,7 +24,7 @@ import java.util.stream.StreamSupport;
 
 import javax.inject.Inject;
 
-import org.apache.james.backends.cassandra.init.CassandraConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 
 import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Row;

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java
index f03ae27..8e20b52 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java
@@ -23,15 +23,13 @@ import java.util.Optional;
 import javax.inject.Inject;
 import javax.inject.Named;
 
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.PropertiesConfiguration;
 import org.apache.commons.text.RandomStringGenerator;
 import org.apache.james.backends.cassandra.components.CassandraModule;
-import org.apache.james.backends.cassandra.init.CassandraSessionConfiguration;
 import org.apache.james.backends.cassandra.init.CassandraTypesProvider;
 import org.apache.james.backends.cassandra.init.ClusterBuilder;
 import org.apache.james.backends.cassandra.init.ClusterWithKeyspaceCreatedFactory;
 import org.apache.james.backends.cassandra.init.SessionWithInitializedTablesFactory;
+import org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
 import org.apache.james.backends.cassandra.utils.FunctionRunnerWithRetry;
 import org.apache.james.util.Host;
 
@@ -51,7 +49,7 @@ public final class CassandraCluster implements AutoCloseable {
     private CassandraTypesProvider typesProvider;
     private Cluster cluster;
     private String keyspace;
-    private CassandraSessionConfiguration cassandraSessionConfiguration;
+    private ClusterConfiguration clusterConfiguration;
 
     public static CassandraCluster create(CassandraModule module, String host, int port) {
         return new CassandraCluster(module, host, port);
@@ -70,15 +68,13 @@ public final class CassandraCluster implements AutoCloseable {
                 .port(port)
                 .build();
             keyspace = new RandomStringGenerator.Builder().withinRange('a', 'z').build().generate(10);
-            cassandraSessionConfiguration = () -> {
-                PropertiesConfiguration conf = new PropertiesConfiguration();
-                conf.addProperty("cassandra.nodes", host + ":" + port);
-                conf.addProperty("cassandra.keyspace", keyspace);
-                conf.addProperty("cassandra.replication.factor", 1);
-                conf.addProperty("cassandra.retryConnection.maxRetries", 10);
-                conf.addProperty("cassandra.retryConnection", 5000);
-                return conf;
-            };
+            clusterConfiguration = ClusterConfiguration.builder()
+                .host(Host.from(host, port))
+                .keyspace(keyspace)
+                .replicationFactor(1)
+                .maxRetry(10)
+                .minDelay(5000)
+                .build();
             session = new FunctionRunnerWithRetry(MAX_RETRY).executeAndRetrieveObject(CassandraCluster.this::tryInitializeSession);
             typesProvider = new CassandraTypesProvider(module, session);
         } catch (Exception exception) {
@@ -97,12 +93,10 @@ public final class CassandraCluster implements AutoCloseable {
                 .replicationFactor(REPLICATION_FACTOR)
                 .disableDurableWrites()
                 .clusterWithInitializedKeyspace();
-            return Optional.of(new SessionWithInitializedTablesFactory(cassandraSessionConfiguration, clusterWithInitializedKeyspace, module).createSession(clusterWithInitializedKeyspace, keyspace));
+            return Optional.of(new SessionWithInitializedTablesFactory(clusterConfiguration, clusterWithInitializedKeyspace, module).createSession(clusterWithInitializedKeyspace, keyspace));
         } catch (NoHostAvailableException exception) {
             sleep(SLEEP_BEFORE_RETRY);
             return Optional.empty();
-        } catch (ConfigurationException e) {
-            throw new RuntimeException(e);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraConfigurationReadingTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraConfigurationReadingTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraConfigurationReadingTest.java
new file mode 100644
index 0000000..efa72f7
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraConfigurationReadingTest.java
@@ -0,0 +1,60 @@
+/****************************************************************
+ * 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.cassandra.init;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.junit.Test;
+
+public class CassandraConfigurationReadingTest {
+
+    @Test
+    public void provideCassandraConfigurationShouldReturnDefaultOnEmptyConfigurationFile() {
+        CassandraConfiguration configuration = CassandraConfiguration.from(new PropertiesConfiguration());
+
+        assertThat(configuration).isEqualTo(CassandraConfiguration.DEFAULT_CONFIGURATION);
+    }
+
+    @Test
+    public void provideCassandraConfigurationShouldReturnRightConfigurationFile() throws ConfigurationException {
+        CassandraConfiguration configuration = CassandraConfiguration.from(new PropertiesConfiguration(
+            ClassLoader.getSystemResource("cassandra.properties")));
+
+        assertThat(configuration)
+            .isEqualTo(CassandraConfiguration.builder()
+                .aclMaxRetry(1)
+                .modSeqMaxRetry(2)
+                .uidMaxRetry(3)
+                .flagsUpdateMessageMaxRetry(4)
+                .flagsUpdateMessageIdMaxRetry(5)
+                .fetchNextPageInAdvanceRow(6)
+                .flagsUpdateChunkSize(7)
+                .messageReadChunkSize(8)
+                .expungeChunkSize(9)
+                .blobPartSize(10)
+                .attachmentV2MigrationReadTimeout(11)
+                .messageAttachmentIdsReadTimeout(12)
+                .build());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraConfigurationTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraConfigurationTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraConfigurationTest.java
index 6c2b4ce..2a60cad 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraConfigurationTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/CassandraConfigurationTest.java
@@ -22,6 +22,7 @@ package org.apache.james.backends.cassandra.init;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.assertj.core.api.JUnitSoftAssertions;
 import org.junit.Rule;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/QueryLoggerConfigurationTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/QueryLoggerConfigurationTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/QueryLoggerConfigurationTest.java
new file mode 100644
index 0000000..012ab24
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/QueryLoggerConfigurationTest.java
@@ -0,0 +1,62 @@
+/****************************************************************
+ * 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.cassandra.init;
+
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.QueryLoggerConfiguration;
+import org.junit.Test;
+
+public class QueryLoggerConfigurationTest {
+
+    @Test
+    public void fromShouldNotThrowWithMinimalConfigAboutAConstantThresholdSlowQueryLogger() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("cassandra.query.logger.constant.threshold", 100);
+
+        assertThatCode(() -> QueryLoggerConfiguration.from(configuration))
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    public void fromShouldNotThrowWithPersonalizedConfigAboutPercentileSlowQuerryLogger() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+
+        configuration.addProperty("cassandra.query.slow.query.latency.threshold.percentile", 90);
+        configuration.addProperty("cassandra.query.logger.max.logged.parameters", 9);
+        configuration.addProperty("cassandra.query.logger.max.query.string.length", 9000);
+        configuration.addProperty("cassandra.query.logger.max.parameter.value.length", 90);
+
+        assertThatCode(() -> QueryLoggerConfiguration.from(configuration))
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    public void fromShouldThrowIfConfigAboutLoggerIsInvalid() {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("cassandra.query.slow.query.latency.threshold.percentile", 90);
+        configuration.addProperty("cassandra.query.logger.constant.threshold", 100);
+
+        assertThatThrownBy(() -> QueryLoggerConfiguration.from(configuration))
+            .isInstanceOf(IllegalStateException.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/backends-common/cassandra/src/test/resources/cassandra.properties
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/resources/cassandra.properties b/backends-common/cassandra/src/test/resources/cassandra.properties
new file mode 100644
index 0000000..5a37b4e
--- /dev/null
+++ b/backends-common/cassandra/src/test/resources/cassandra.properties
@@ -0,0 +1,12 @@
+mailbox.max.retry.acl=1
+mailbox.max.retry.modseq=2
+mailbox.max.retry.uid=3
+mailbox.max.retry.message.flags.update=4
+mailbox.max.retry.message.id.flags.update=5
+fetch.advance.row.count=6
+chunk.size.flags.update=7
+chunk.size.message.read=8
+chunk.size.expunge=9
+mailbox.blob.part.size=10
+attachment.v2.migration.read.timeout=11
+message.attachmentids.read.timeout=12

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
index 71caf9c..0eda3c3 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
@@ -21,7 +21,7 @@ package org.apache.james.mailbox.cassandra;
 
 import javax.inject.Inject;
 
-import org.apache.james.backends.cassandra.init.CassandraConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.blob.api.ObjectStore;
 import org.apache.james.mailbox.MailboxSession;

http://git-wip-us.apache.org/repos/asf/james-project/blob/c767bf79/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
index 2d4c997..7f2bb6a 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
@@ -33,7 +33,7 @@ import java.util.function.Function;
 
 import javax.inject.Inject;
 
-import org.apache.james.backends.cassandra.init.CassandraConfiguration;
+import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
 import org.apache.james.backends.cassandra.utils.FunctionRunnerWithRetry;
 import org.apache.james.backends.cassandra.utils.LightweightTransactionException;


---------------------------------------------------------------------
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