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

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

commit e88a52e5120d6d51eba4706a500e4b3888134c42
Author: Gautier DI FOLCO <gdifo...@linagora.com>
AuthorDate: Tue Jun 16 18:35:19 2020 +0200

    JAMES-3224 Introduce CassandraConsistenciesConfiguration
---
 .../init/configuration/CassandraConfiguration.java | 79 +++++++++++++++++--
 .../CassandraConsistenciesConfiguration.java       | 90 ++++++++++++++++++++++
 .../init/CassandraConfigurationReadingTest.java    |  2 +
 .../cassandra/init/CassandraConfigurationTest.java | 20 +++++
 .../CassandraConsistenciesConfigurationTest.java   | 84 ++++++++++++++++++++
 .../configuration-reader-test/cassandra.properties |  2 +
 .../destination/conf/cassandra.properties          |  7 ++
 .../destination/conf/cassandra.properties          |  7 ++
 .../destination/conf/cassandra.properties          |  7 ++
 .../destination/conf/cassandra.properties          |  7 ++
 .../modules/mailbox/CassandraSessionModule.java    |  8 ++
 src/site/xdoc/server/config-cassandra.xml          |  6 ++
 12 files changed, 314 insertions(+), 5 deletions(-)

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
index 2681d45..42bbce0 100644
--- 
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
@@ -21,17 +21,23 @@ package 
org.apache.james.backends.cassandra.init.configuration;
 
 import static java.lang.Math.toIntExact;
 
+import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
 
 import org.apache.commons.configuration2.Configuration;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 
 public class CassandraConfiguration {
+    private static final org.slf4j.Logger LOGGER = 
LoggerFactory.getLogger(CassandraConfiguration.class);
+
     public static final int DEFAULT_MESSAGE_CHUNK_SIZE_ON_READ = 100;
     public static final int DEFAULT_EXPUNGE_BATCH_SIZE = 50;
     public static final int DEFAULT_UPDATE_FLAGS_BATCH_SIZE = 20;
@@ -44,7 +50,10 @@ public class CassandraConfiguration {
     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 String DEFAULT_CONSISTENCY_LEVEL_REGULAR = "QUORUM";
+    public static final String 
DEFAULT_CONSISTENCY_LEVEL_LIGHTWEIGHT_TRANSACTION = "SERIAL";
+    public static final List<String> VALID_CONSISTENCY_LEVEL_REGULAR = 
ImmutableList.of("QUORUM", "LOCAL_QUORUM", "EACH_QUORUM");
+    public static final List<String> 
VALID_CONSISTENCY_LEVEL_LIGHTWEIGHT_TRANSACTION = ImmutableList.of("SERIAL", 
"LOCAL_SERIAL");
 
     private static final String MAILBOX_MAX_RETRY_ACL = 
"mailbox.max.retry.acl";
     private static final String MAILBOX_MAX_RETRY_MODSEQ = 
"mailbox.max.retry.modseq";
@@ -57,6 +66,8 @@ public class CassandraConfiguration {
     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";
+    private static final String CONSISTENCY_LEVEL_REGULAR = 
"cassandra.consistency_level.regular";
+    private static final String CONSISTENCY_LEVEL_LIGHTWEIGHT_TRANSACTION = 
"cassandra.consistency_level.lightweight_transaction";
 
     public static final CassandraConfiguration DEFAULT_CONFIGURATION = 
builder().build();
 
@@ -72,6 +83,8 @@ public class CassandraConfiguration {
         private Optional<Integer> blobPartSize = Optional.empty();
         private Optional<Integer> attachmentV2MigrationReadTimeout = 
Optional.empty();
         private Optional<Integer> messageAttachmentIdsReadTimeout = 
Optional.empty();
+        private Optional<String> consistencyLevelRegular = Optional.empty();
+        private Optional<String> consistencyLevelLightweightTransaction = 
Optional.empty();
 
         public Builder messageReadChunkSize(int value) {
             Preconditions.checkArgument(value > 0, "messageReadChunkSize needs 
to be strictly positive");
@@ -194,7 +207,39 @@ public class CassandraConfiguration {
             return this;
         }
 
+        public Builder consistencyLevelRegular(String value) {
+            
Preconditions.checkArgument(VALID_CONSISTENCY_LEVEL_REGULAR.contains(value),
+                "consistencyLevelRegular needs to be one of the following: " + 
String.join(", ", VALID_CONSISTENCY_LEVEL_REGULAR));
+            this.consistencyLevelRegular = Optional.of(value);
+            return this;
+        }
+
+        public Builder consistencyLevelLightweightTransaction(String value) {
+            
Preconditions.checkArgument(VALID_CONSISTENCY_LEVEL_LIGHTWEIGHT_TRANSACTION.contains(value),
+                "consistencyLevelLightweightTransaction needs to be one of the 
following: " + String.join(", ", 
VALID_CONSISTENCY_LEVEL_LIGHTWEIGHT_TRANSACTION));
+            this.consistencyLevelLightweightTransaction = Optional.of(value);
+            return this;
+        }
+
+        public Builder consistencyLevelRegular(Optional<String> value) {
+            value.ifPresent(this::consistencyLevelRegular);
+            return this;
+        }
+
+        public Builder consistencyLevelLightweightTransaction(Optional<String> 
value) {
+            value.ifPresent(this::consistencyLevelLightweightTransaction);
+            return this;
+        }
+
         public CassandraConfiguration build() {
+            String consistencyLevelRegular = 
this.consistencyLevelRegular.orElse(DEFAULT_CONSISTENCY_LEVEL_REGULAR);
+            String consistencyLevelLightweightTransaction = 
this.consistencyLevelLightweightTransaction.orElse(DEFAULT_CONSISTENCY_LEVEL_LIGHTWEIGHT_TRANSACTION);
+            Predicate<String> isLocal = consistencyLevel -> 
consistencyLevel.startsWith("LOCAL_");
+            if (isLocal.test(consistencyLevelRegular) != 
isLocal.test(consistencyLevelLightweightTransaction)) {
+                LOGGER.warn("The consistency levels may not be properly 
configured, one is local and the other not: "
+                    + "regular = '{}' and lightweight transaction = '{}'", 
consistencyLevelRegular, consistencyLevelLightweightTransaction);
+            }
+
             return new 
CassandraConfiguration(aclMaxRetry.orElse(DEFAULT_ACL_MAX_RETRY),
                 
messageReadChunkSize.orElse(DEFAULT_MESSAGE_CHUNK_SIZE_ON_READ),
                 expungeChunkSize.orElse(DEFAULT_EXPUNGE_BATCH_SIZE),
@@ -205,7 +250,9 @@ public class CassandraConfiguration {
                 
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));
+                
messageAttachmentIdsReadTimeout.orElse(DEFAULT_MESSAGE_ATTACHMENT_ID_MIGRATION_READ_TIMEOUT),
+                consistencyLevelRegular,
+                consistencyLevelLightweightTransaction);
         }
     }
 
@@ -237,6 +284,10 @@ public class CassandraConfiguration {
                 
propertiesConfiguration.getInteger(ATTACHMENT_V2_MIGRATION_READ_TIMEOUT, null)))
             .messageAttachmentIdsReadTimeout(Optional.ofNullable(
                 
propertiesConfiguration.getInteger(MESSAGE_ATTACHMENTID_READ_TIMEOUT, null)))
+            .consistencyLevelRegular(Optional.ofNullable(
+                    
propertiesConfiguration.getString(CONSISTENCY_LEVEL_REGULAR)))
+            .consistencyLevelLightweightTransaction(Optional.ofNullable(
+                    
propertiesConfiguration.getString(CONSISTENCY_LEVEL_LIGHTWEIGHT_TRANSACTION)))
             .build();
     }
 
@@ -251,12 +302,15 @@ public class CassandraConfiguration {
     private final int blobPartSize;
     private final int attachmentV2MigrationReadTimeout;
     private final int messageAttachmentIdsReadTimeout;
+    private final String consistencyLevelRegular;
+    private final String consistencyLevelLightweightTransaction;
 
     @VisibleForTesting
     CassandraConfiguration(int aclMaxRetry, int messageReadChunkSize, int 
expungeChunkSize,
                            int flagsUpdateMessageIdMaxRetry, int 
flagsUpdateMessageMaxRetry,
                            int modSeqMaxRetry, int uidMaxRetry, int 
fetchNextPageInAdvanceRow,
-                           int blobPartSize, final int 
attachmentV2MigrationReadTimeout, int messageAttachmentIdsReadTimeout) {
+                           int blobPartSize, final int 
attachmentV2MigrationReadTimeout, int messageAttachmentIdsReadTimeout,
+                           String consistencyLevelRegular, String 
consistencyLevelLightweightTransaction) {
         this.aclMaxRetry = aclMaxRetry;
         this.messageReadChunkSize = messageReadChunkSize;
         this.expungeChunkSize = expungeChunkSize;
@@ -268,6 +322,8 @@ public class CassandraConfiguration {
         this.blobPartSize = blobPartSize;
         this.attachmentV2MigrationReadTimeout = 
attachmentV2MigrationReadTimeout;
         this.messageAttachmentIdsReadTimeout = messageAttachmentIdsReadTimeout;
+        this.consistencyLevelRegular = consistencyLevelRegular;
+        this.consistencyLevelLightweightTransaction = 
consistencyLevelLightweightTransaction;
     }
 
     public int getBlobPartSize() {
@@ -314,6 +370,14 @@ public class CassandraConfiguration {
         return messageAttachmentIdsReadTimeout;
     }
 
+    public String getConsistencyLevelRegular() {
+        return consistencyLevelRegular;
+    }
+
+    public String getConsistencyLevelLightweightTransaction() {
+        return consistencyLevelLightweightTransaction;
+    }
+
     @Override
     public final boolean equals(Object o) {
         if (o instanceof CassandraConfiguration) {
@@ -329,7 +393,9 @@ public class CassandraConfiguration {
                 && Objects.equals(this.fetchNextPageInAdvanceRow, 
that.fetchNextPageInAdvanceRow)
                 && Objects.equals(this.blobPartSize, that.blobPartSize)
                 && Objects.equals(this.attachmentV2MigrationReadTimeout, 
that.attachmentV2MigrationReadTimeout)
-                && Objects.equals(this.messageAttachmentIdsReadTimeout, 
that.messageAttachmentIdsReadTimeout);
+                && Objects.equals(this.messageAttachmentIdsReadTimeout, 
that.messageAttachmentIdsReadTimeout)
+                && Objects.equals(this.consistencyLevelRegular, 
that.consistencyLevelRegular)
+                && Objects.equals(this.consistencyLevelLightweightTransaction, 
that.consistencyLevelLightweightTransaction);
         }
         return false;
     }
@@ -338,7 +404,8 @@ public class CassandraConfiguration {
     public final int hashCode() {
         return Objects.hash(aclMaxRetry, messageReadChunkSize, 
expungeChunkSize, flagsUpdateMessageIdMaxRetry,
             flagsUpdateMessageMaxRetry, modSeqMaxRetry, uidMaxRetry, 
fetchNextPageInAdvanceRow,
-            blobPartSize, attachmentV2MigrationReadTimeout, 
messageAttachmentIdsReadTimeout);
+            blobPartSize, attachmentV2MigrationReadTimeout, 
messageAttachmentIdsReadTimeout,
+            consistencyLevelRegular, consistencyLevelLightweightTransaction);
     }
 
     @Override
@@ -355,6 +422,8 @@ public class CassandraConfiguration {
             .add("blobPartSize", blobPartSize)
             .add("attachmentV2MigrationReadTimeout", 
attachmentV2MigrationReadTimeout)
             .add("messageAttachmentIdsReadTimeout", 
messageAttachmentIdsReadTimeout)
+            .add("consistencyLevelRegular", consistencyLevelRegular)
+            .add("consistencyLevelLightweightTransaction", 
consistencyLevelLightweightTransaction)
             .toString();
     }
 }
diff --git 
a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConsistenciesConfiguration.java
 
b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConsistenciesConfiguration.java
new file mode 100644
index 0000000..e1f71e6
--- /dev/null
+++ 
b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/init/configuration/CassandraConsistenciesConfiguration.java
@@ -0,0 +1,90 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ * http://www.apache.org/licenses/LICENSE-2.0                   *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ***************************************************************/
+
+package org.apache.james.backends.cassandra.init.configuration;
+
+import java.util.Objects;
+
+import com.datastax.driver.core.ConsistencyLevel;
+import com.google.common.base.MoreObjects;
+
+public class CassandraConsistenciesConfiguration {
+    public static ConsistencyLevel fromString(String value) {
+        switch (value) {
+            case "QUORUM":
+                return ConsistencyLevel.QUORUM;
+            case "LOCAL_QUORUM":
+                return ConsistencyLevel.LOCAL_QUORUM;
+            case "EACH_QUORUM":
+                return ConsistencyLevel.EACH_QUORUM;
+            case "SERIAL":
+                return ConsistencyLevel.SERIAL;
+            case "LOCAL_SERIAL":
+                return ConsistencyLevel.LOCAL_SERIAL;
+        }
+        throw new IllegalArgumentException("'" + value + "' is not a value 
ConsistencyLevel");
+    }
+
+    public static CassandraConsistenciesConfiguration 
fromConfiguration(CassandraConfiguration configuration) {
+        return new CassandraConsistenciesConfiguration(
+            fromString(configuration.getConsistencyLevelRegular()),
+            
fromString(configuration.getConsistencyLevelLightweightTransaction()));
+    }
+
+    private final ConsistencyLevel regular;
+    private final ConsistencyLevel lightweightTransaction;
+
+    private CassandraConsistenciesConfiguration(ConsistencyLevel regular,
+                                                ConsistencyLevel 
lightweightTransaction) {
+        this.regular = regular;
+        this.lightweightTransaction = lightweightTransaction;
+    }
+
+    public ConsistencyLevel getRegular() {
+        return regular;
+    }
+
+    public ConsistencyLevel getLightweightTransaction() {
+        return lightweightTransaction;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof CassandraConsistenciesConfiguration) {
+            CassandraConsistenciesConfiguration that = 
(CassandraConsistenciesConfiguration) o;
+
+            return Objects.equals(this.regular, that.regular)
+                && Objects.equals(this.lightweightTransaction, 
that.lightweightTransaction);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(regular, lightweightTransaction);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("consistencyLevelRegular", regular)
+            .add("consistencyLevelLightweightTransaction", 
lightweightTransaction)
+            .toString();
+    }
+}
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
index a6f5995..cf3b28d 100644
--- 
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
@@ -60,6 +60,8 @@ class CassandraConfigurationReadingTest {
                 .blobPartSize(9)
                 .attachmentV2MigrationReadTimeout(10)
                 .messageAttachmentIdsReadTimeout(11)
+                .consistencyLevelRegular("LOCAL_QUORUM")
+                .consistencyLevelLightweightTransaction("LOCAL_SERIAL")
                 .build());
     }
 
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 678b7f7..ce9f638 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
@@ -183,6 +183,20 @@ class CassandraConfigurationTest {
     }
 
     @Test
+    void consistencyLevelRegularShouldThrowOnNotSupportedValue() {
+        assertThatThrownBy(() -> CassandraConfiguration.builder()
+            .consistencyLevelRegular("ALL"))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    void 
consistencyLevelLightweightTransactionShouldThrowOnNotSupportedValue() {
+        assertThatThrownBy(() -> CassandraConfiguration.builder()
+                .consistencyLevelLightweightTransaction("ALL"))
+                .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
     void builderShouldCreateTheRightObject() {
         int aclMaxRetry = 1;
         int modSeqMaxRetry = 2;
@@ -195,6 +209,8 @@ class CassandraConfigurationTest {
         int blobPartSize = 10;
         int attachmentV2MigrationReadTimeout = 11;
         int messageAttachmentIdReadTimeout = 12;
+        String consistencyLevelRegular = "LOCAL_QUORUM";
+        String consistencyLevelLightweightTransaction = "LOCAL_SERIAL";
 
         CassandraConfiguration configuration = CassandraConfiguration.builder()
             .aclMaxRetry(aclMaxRetry)
@@ -208,6 +224,8 @@ class CassandraConfigurationTest {
             .blobPartSize(blobPartSize)
             .attachmentV2MigrationReadTimeout(attachmentV2MigrationReadTimeout)
             .messageAttachmentIdsReadTimeout(messageAttachmentIdReadTimeout)
+            .consistencyLevelRegular(consistencyLevelRegular)
+            
.consistencyLevelLightweightTransaction(consistencyLevelLightweightTransaction)
             .build();
 
         SoftAssertions.assertSoftly(softly -> {
@@ -222,6 +240,8 @@ class CassandraConfigurationTest {
             
softly.assertThat(configuration.getBlobPartSize()).isEqualTo(blobPartSize);
             
softly.assertThat(configuration.getAttachmentV2MigrationReadTimeout()).isEqualTo(attachmentV2MigrationReadTimeout);
             
softly.assertThat(configuration.getMessageAttachmentIdsReadTimeout()).isEqualTo(messageAttachmentIdReadTimeout);
+            
softly.assertThat(configuration.getConsistencyLevelRegular()).isEqualTo(consistencyLevelRegular);
+            
softly.assertThat(configuration.getConsistencyLevelLightweightTransaction()).isEqualTo(consistencyLevelLightweightTransaction);
         });
     }
 
diff --git 
a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/configuration/CassandraConsistenciesConfigurationTest.java
 
b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/configuration/CassandraConsistenciesConfigurationTest.java
new file mode 100644
index 0000000..4e282dc
--- /dev/null
+++ 
b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/init/configuration/CassandraConsistenciesConfigurationTest.java
@@ -0,0 +1,84 @@
+/****************************************************************
+ * 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 org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.stream.Stream;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import com.datastax.driver.core.ConsistencyLevel;
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class CassandraConsistenciesConfigurationTest {
+    @Test
+    void cassandraConsistenciesConfigurationShouldRespectBeanContract() {
+        EqualsVerifier.forClass(CassandraConsistenciesConfiguration.class)
+            .verify();
+    }
+
+    @Test
+    void fromStringShouldThrowOnInvalidValue() {
+        assertThatThrownBy(() -> 
CassandraConsistenciesConfiguration.fromString("INVALID"))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @ParameterizedTest
+    @MethodSource
+    void fromStringShouldInstantiateTheRightValue(String rawValue, 
ConsistencyLevel expected) {
+        assertThat(CassandraConsistenciesConfiguration.fromString(rawValue))
+            .isEqualTo(expected);
+    }
+
+    private static Stream<Arguments> 
fromStringShouldInstantiateTheRightValue() {
+        return Stream.of(
+            Arguments.of("QUORUM", ConsistencyLevel.QUORUM),
+            Arguments.of("LOCAL_QUORUM", ConsistencyLevel.LOCAL_QUORUM),
+            Arguments.of("EACH_QUORUM", ConsistencyLevel.EACH_QUORUM),
+            Arguments.of("SERIAL", ConsistencyLevel.SERIAL),
+            Arguments.of("LOCAL_SERIAL", ConsistencyLevel.LOCAL_SERIAL)
+        );
+    }
+
+    @Test
+    void fromConfigurationShouldTakeTheValues() {
+        String consistencyLevelRegular = "LOCAL_QUORUM";
+        String consistencyLevelLightweightTransaction = "LOCAL_SERIAL";
+
+        CassandraConfiguration configuration = CassandraConfiguration.builder()
+            .consistencyLevelRegular(consistencyLevelRegular)
+            
.consistencyLevelLightweightTransaction(consistencyLevelLightweightTransaction)
+            .build();
+
+        CassandraConsistenciesConfiguration consistenciesConfiguration = 
CassandraConsistenciesConfiguration
+            .fromConfiguration(configuration);
+
+        SoftAssertions.assertSoftly(softly -> {
+            
softly.assertThat(consistenciesConfiguration.getRegular()).isEqualTo(ConsistencyLevel.LOCAL_QUORUM);
+            
softly.assertThat(consistenciesConfiguration.getLightweightTransaction()).isEqualTo(ConsistencyLevel.LOCAL_SERIAL);
+        });
+    }
+}
\ No newline at end of file
diff --git 
a/backends-common/cassandra/src/test/resources/configuration-reader-test/cassandra.properties
 
b/backends-common/cassandra/src/test/resources/configuration-reader-test/cassandra.properties
index 27f4430..10ca4dd 100644
--- 
a/backends-common/cassandra/src/test/resources/configuration-reader-test/cassandra.properties
+++ 
b/backends-common/cassandra/src/test/resources/configuration-reader-test/cassandra.properties
@@ -9,3 +9,5 @@ chunk.size.expunge=8
 mailbox.blob.part.size=9
 attachment.v2.migration.read.timeout=10
 message.attachmentids.read.timeout=11
+cassandra.consistency_level.regular=LOCAL_QUORUM
+cassandra.consistency_level.lightweight_transaction=LOCAL_SERIAL
\ No newline at end of file
diff --git 
a/dockerfiles/run/guice/cassandra-ldap/destination/conf/cassandra.properties 
b/dockerfiles/run/guice/cassandra-ldap/destination/conf/cassandra.properties
index 0e19020..c1bbe41 100644
--- a/dockerfiles/run/guice/cassandra-ldap/destination/conf/cassandra.properties
+++ b/dockerfiles/run/guice/cassandra-ldap/destination/conf/cassandra.properties
@@ -23,3 +23,10 @@ cassandra.retryConnection.minDelay=5000
 # chunk.size.message.read=100
 # chunk.size.expunge=100
 # mailbox.blob.part.size=102400
+
+## Consistency levels used for common queries
+## Read 
https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/dml/dmlConfigConsistency.html
+# QUORUM, LOCAL_QUORUM, or EACH_QUORUM
+# cassandra.consistency_level.regular=QUORUM
+# SERIAL or LOCAL_SERIAL
+# cassandra.consistency_level.lightweight_transaction=SERIAL
diff --git 
a/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/cassandra.properties
 
b/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/cassandra.properties
index 137b2cc..e7dff97 100644
--- 
a/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/cassandra.properties
+++ 
b/dockerfiles/run/guice/cassandra-rabbitmq-ldap/destination/conf/cassandra.properties
@@ -33,3 +33,10 @@ cassandra.retryConnection.minDelay=5000
 # chunk.size.message.read=100
 # chunk.size.expunge=100
 # mailbox.blob.part.size=102400
+
+## Consistency levels used for common queries
+## Read 
https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/dml/dmlConfigConsistency.html
+# QUORUM, LOCAL_QUORUM, or EACH_QUORUM
+# cassandra.consistency_level.regular=QUORUM
+# SERIAL or LOCAL_SERIAL
+# cassandra.consistency_level.lightweight_transaction=SERIAL
diff --git 
a/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/cassandra.properties
 
b/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/cassandra.properties
index 137b2cc..e7dff97 100644
--- 
a/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/cassandra.properties
+++ 
b/dockerfiles/run/guice/cassandra-rabbitmq/destination/conf/cassandra.properties
@@ -33,3 +33,10 @@ cassandra.retryConnection.minDelay=5000
 # chunk.size.message.read=100
 # chunk.size.expunge=100
 # mailbox.blob.part.size=102400
+
+## Consistency levels used for common queries
+## Read 
https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/dml/dmlConfigConsistency.html
+# QUORUM, LOCAL_QUORUM, or EACH_QUORUM
+# cassandra.consistency_level.regular=QUORUM
+# SERIAL or LOCAL_SERIAL
+# cassandra.consistency_level.lightweight_transaction=SERIAL
diff --git 
a/dockerfiles/run/guice/cassandra/destination/conf/cassandra.properties 
b/dockerfiles/run/guice/cassandra/destination/conf/cassandra.properties
index b96beef..1e1bae2 100644
--- a/dockerfiles/run/guice/cassandra/destination/conf/cassandra.properties
+++ b/dockerfiles/run/guice/cassandra/destination/conf/cassandra.properties
@@ -33,3 +33,10 @@ cassandra.retryConnection.minDelay=5000
 # chunk.size.message.read=100
 # chunk.size.expunge=100
 # mailbox.blob.part.size=102400
+
+## Consistency levels used for common queries
+## Read 
https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/dml/dmlConfigConsistency.html
+# QUORUM, LOCAL_QUORUM, or EACH_QUORUM
+# cassandra.consistency_level.regular=QUORUM
+# SERIAL or LOCAL_SERIAL
+# cassandra.consistency_level.lightweight_transaction=SERIAL
diff --git 
a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
 
b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
index d8004f2..165ce05 100644
--- 
a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
+++ 
b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
@@ -29,6 +29,7 @@ import 
org.apache.james.backends.cassandra.init.KeyspaceFactory;
 import org.apache.james.backends.cassandra.init.ResilientClusterProvider;
 import 
org.apache.james.backends.cassandra.init.SessionWithInitializedTablesFactory;
 import 
org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import 
org.apache.james.backends.cassandra.init.configuration.CassandraConsistenciesConfiguration;
 import 
org.apache.james.backends.cassandra.init.configuration.ClusterConfiguration;
 import 
org.apache.james.backends.cassandra.init.configuration.KeyspaceConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraHealthCheck;
@@ -135,6 +136,13 @@ public class CassandraSessionModule extends AbstractModule 
{
         }
     }
 
+    @VisibleForTesting
+    @Provides
+    @Singleton
+    CassandraConsistenciesConfiguration 
provideCassandraConsistenciesConfiguration(CassandraConfiguration 
configuration) {
+        return 
CassandraConsistenciesConfiguration.fromConfiguration(configuration);
+    }
+
     @Provides
     @Singleton
     ClusterConfiguration provideClusterConfiguration(PropertiesProvider 
propertiesProvider) throws ConfigurationException {
diff --git a/src/site/xdoc/server/config-cassandra.xml 
b/src/site/xdoc/server/config-cassandra.xml
index 34a05df..e725404 100644
--- a/src/site/xdoc/server/config-cassandra.xml
+++ b/src/site/xdoc/server/config-cassandra.xml
@@ -136,6 +136,12 @@
         <dd>Optional. Defaults to 50.<br/> Controls the number of messages to 
be expunged in parallel.</dd>
         <dt><strong>mailbox.blob.part.size</strong></dt>
         <dd>Optional. Defaults to 102400 (100KB).<br/> Controls the size of 
blob parts used to store messages.</dd>
+
+        <dt><strong>Allows specifying the driver default consistency 
level.</strong></dt>
+        <dt><strong>cassandra.consistency_level.regular</strong></dt>
+        <dd>Optional. Defaults to QUORUM.<br/> <a 
href="https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/dml/dmlConfigConsistency.html";>QUORUM,
 LOCAL_QUORUM, or EACH_QUORUM</a>.</dd>
+        
<dt><strong>cassandra.consistency_level.lightweight_transaction</strong></dt>
+        <dd>Optional. Defaults to SERIAL.<br/> <a 
href="https://docs.datastax.com/en/cassandra-oss/3.x/cassandra/dml/dmlConfigConsistency.html";>SERIAL
 or LOCAL_SERIAL</a>.</dd>
       </dl>
 
 


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

Reply via email to