JAMES-1968 Rework CassandraSieveRepository

 - Rely on denormalization instead of INDEX
 - Use FutureUtils
 - Tests DAOs
 - Improve APIs


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

Branch: refs/heads/master
Commit: f28cc423e9a78e04dba25fe7fec3d2d5c42443c9
Parents: e4e1462
Author: benwa <btell...@linagora.com>
Authored: Thu Mar 16 20:24:45 2017 +0700
Committer: benwa <btell...@linagora.com>
Committed: Wed Mar 22 07:11:14 2017 +0700

----------------------------------------------------------------------
 .../cassandra/host/CassandraHostSystem.java     |   4 +-
 .../cassandra/CassandraActiveScriptDAO.java     |  89 +++++++++++
 .../sieve/cassandra/CassandraSieveDAO.java      | 157 ++++++-------------
 .../cassandra/CassandraSieveRepository.java     |  89 +++++++----
 .../CassandraSieveRepositoryModule.java         |  15 +-
 .../sieve/cassandra/model/ActiveScriptInfo.java |  43 +++++
 .../model/ScriptContentAndActivation.java       |  39 -----
 .../tables/CassandraSieveActiveTable.java       |  30 ++++
 .../cassandra/tables/CassandraSieveTable.java   |   1 -
 .../cassandra/CassandraActiveScriptDAOTest.java |  97 ++++++++++++
 .../sieve/cassandra/CassandraSieveDAOTest.java  | 143 +++++++++++++++++
 .../cassandra/CassandraSieveQuotaDAOTest.java   | 149 ++++++++++++++++++
 .../cassandra/CassandraSieveRepositoryTest.java |  48 +-----
 13 files changed, 676 insertions(+), 228 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/mpt/impl/managesieve/cassandra/src/test/java/org/apache/james/mpt/managesieve/cassandra/host/CassandraHostSystem.java
----------------------------------------------------------------------
diff --git 
a/mpt/impl/managesieve/cassandra/src/test/java/org/apache/james/mpt/managesieve/cassandra/host/CassandraHostSystem.java
 
b/mpt/impl/managesieve/cassandra/src/test/java/org/apache/james/mpt/managesieve/cassandra/host/CassandraHostSystem.java
index fae007c..a771517 100644
--- 
a/mpt/impl/managesieve/cassandra/src/test/java/org/apache/james/mpt/managesieve/cassandra/host/CassandraHostSystem.java
+++ 
b/mpt/impl/managesieve/cassandra/src/test/java/org/apache/james/mpt/managesieve/cassandra/host/CassandraHostSystem.java
@@ -21,6 +21,7 @@ package org.apache.james.mpt.managesieve.cassandra.host;
 
 import org.apache.james.backends.cassandra.init.CassandraModuleComposite;
 import org.apache.james.mpt.host.JamesManageSieveHostSystem;
+import org.apache.james.sieve.cassandra.CassandraActiveScriptDAO;
 import org.apache.james.sieve.cassandra.CassandraSieveDAO;
 import org.apache.james.sieve.cassandra.CassandraSieveQuotaDAO;
 import org.apache.james.sieve.cassandra.CassandraSieveRepository;
@@ -43,7 +44,8 @@ public class CassandraHostSystem extends 
JamesManageSieveHostSystem {
     protected static SieveRepository createSieveRepository() throws Exception {
         return new CassandraSieveRepository(
             new CassandraSieveDAO(CASSANDRA_CLUSTER.getConf()),
-            new CassandraSieveQuotaDAO(CASSANDRA_CLUSTER.getConf()));
+            new CassandraSieveQuotaDAO(CASSANDRA_CLUSTER.getConf()),
+            new CassandraActiveScriptDAO(CASSANDRA_CLUSTER.getConf()));
     }
 
     protected static UsersRepository createUsersRepository() {

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
new file mode 100644
index 0000000..38ca130
--- /dev/null
+++ 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAO.java
@@ -0,0 +1,89 @@
+/****************************************************************
+ * 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.sieve.cassandra;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.delete;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.now;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
+import static 
org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable.DATE;
+import static 
org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable.TABLE_NAME;
+import static 
org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable.SCRIPT_NAME;
+import static 
org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable.USER_NAME;
+
+import java.util.Date;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+import javax.inject.Inject;
+
+import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
+import org.apache.james.sieve.cassandra.model.ActiveScriptInfo;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.Session;
+
+public class CassandraActiveScriptDAO {
+    private final CassandraAsyncExecutor cassandraAsyncExecutor;
+    private final PreparedStatement insertActive;
+    private final PreparedStatement deleteActive;
+    private final PreparedStatement selectActiveName;
+
+    @Inject
+    public CassandraActiveScriptDAO(Session session) {
+        this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
+        this.insertActive = session.prepare(insertInto(TABLE_NAME)
+            .value(SCRIPT_NAME, bindMarker(SCRIPT_NAME))
+            .value(USER_NAME, bindMarker(USER_NAME))
+            .value(DATE, bindMarker(DATE)));
+        this.deleteActive = session.prepare(delete()
+            .from(TABLE_NAME)
+            .where(eq(USER_NAME, bindMarker(USER_NAME))));
+        this.selectActiveName = session.prepare(select(SCRIPT_NAME, DATE)
+            .from(TABLE_NAME)
+            .where(eq(USER_NAME, bindMarker(USER_NAME))));
+    }
+
+    public CompletableFuture<Optional<ActiveScriptInfo>> 
getActiveSctiptInfo(String username) {
+        return cassandraAsyncExecutor.executeSingleRow(
+            selectActiveName.bind()
+                .setString(USER_NAME, username))
+            .thenApply(rowOptional -> rowOptional.map(row -> new 
ActiveScriptInfo(
+                row.getString(SCRIPT_NAME),
+                row.getDate(DATE))));
+    }
+
+    public CompletableFuture<Void> unactivate(String username) {
+        return cassandraAsyncExecutor.executeVoid(
+            deleteActive.bind()
+                .setString(USER_NAME, username));
+    }
+
+    public CompletableFuture<Void> activate(String username, String 
scriptName) {
+        return cassandraAsyncExecutor.executeVoid(
+            insertActive.bind()
+                .setString(USER_NAME, username)
+                .setString(SCRIPT_NAME, scriptName)
+                .setDate(DATE, new Date()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
index 31c3ee6..7dab54a 100644
--- 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
+++ 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveDAO.java
@@ -26,8 +26,14 @@ import static 
com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.set;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.update;
+import static 
org.apache.james.sieve.cassandra.tables.CassandraSieveTable.IS_ACTIVE;
+import static 
org.apache.james.sieve.cassandra.tables.CassandraSieveTable.SCRIPT_CONTENT;
+import static 
org.apache.james.sieve.cassandra.tables.CassandraSieveTable.SCRIPT_NAME;
+import static org.apache.james.sieve.cassandra.tables.CassandraSieveTable.SIZE;
+import static 
org.apache.james.sieve.cassandra.tables.CassandraSieveTable.TABLE_NAME;
+import static 
org.apache.james.sieve.cassandra.tables.CassandraSieveTable.USER_NAME;
+
 
-import java.util.Date;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
@@ -36,10 +42,8 @@ import java.util.stream.Collectors;
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.sieve.cassandra.model.ScriptContentAndActivation;
-import org.apache.james.sieve.cassandra.tables.CassandraSieveTable;
+import org.apache.james.sieve.cassandra.model.Script;
 import org.apache.james.sieverepository.api.ScriptSummary;
-import org.joda.time.DateTime;
 
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
@@ -50,12 +54,8 @@ public class CassandraSieveDAO {
 
     private final CassandraAsyncExecutor cassandraAsyncExecutor;
     private final PreparedStatement insertScriptStatement;
-    private final PreparedStatement selectActiveScriptStatement;
-    private final PreparedStatement selectActiveScriptMetadataStatement;
-    private final PreparedStatement selectActiveScriptNameStatement;
     private final PreparedStatement selectScriptsStatement;
     private final PreparedStatement selectScriptStatement;
-    private final PreparedStatement selectScriptMetadataStatement;
     private final PreparedStatement updateScriptActivationStatement;
     private final PreparedStatement deleteScriptStatement;
 
@@ -64,145 +64,90 @@ public class CassandraSieveDAO {
         this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
 
         insertScriptStatement = session.prepare(
-            insertInto(CassandraSieveTable.TABLE_NAME)
-                .value(CassandraSieveTable.USER_NAME, 
bindMarker(CassandraSieveTable.USER_NAME))
-                .value(CassandraSieveTable.SCRIPT_NAME, 
bindMarker(CassandraSieveTable.SCRIPT_NAME))
-                .value(CassandraSieveTable.SCRIPT_CONTENT, 
bindMarker(CassandraSieveTable.SCRIPT_CONTENT))
-                .value(CassandraSieveTable.IS_ACTIVE, 
bindMarker(CassandraSieveTable.IS_ACTIVE))
-                .value(CassandraSieveTable.SIZE, 
bindMarker(CassandraSieveTable.SIZE))
-                .value(CassandraSieveTable.DATE, 
bindMarker(CassandraSieveTable.DATE)));
-
-        selectActiveScriptStatement = 
session.prepare(getScriptQuery(CassandraSieveTable.SCRIPT_CONTENT, 
CassandraSieveTable.DATE)
-            .and(eq(CassandraSieveTable.IS_ACTIVE, 
bindMarker(CassandraSieveTable.IS_ACTIVE))));
-
-        selectActiveScriptMetadataStatement = 
session.prepare(getScriptQuery(CassandraSieveTable.DATE)
-            .and(eq(CassandraSieveTable.IS_ACTIVE, 
bindMarker(CassandraSieveTable.IS_ACTIVE))));
+            insertInto(TABLE_NAME)
+                .value(USER_NAME, bindMarker(USER_NAME))
+                .value(SCRIPT_NAME, bindMarker(SCRIPT_NAME))
+                .value(SCRIPT_CONTENT, bindMarker(SCRIPT_CONTENT))
+                .value(IS_ACTIVE, bindMarker(IS_ACTIVE))
+                .value(SIZE, bindMarker(SIZE)));
 
-        selectActiveScriptNameStatement = 
session.prepare(getScriptQuery(CassandraSieveTable.SCRIPT_NAME)
-            .and(eq(CassandraSieveTable.IS_ACTIVE, 
bindMarker(CassandraSieveTable.IS_ACTIVE))));
+        selectScriptsStatement = session.prepare(getScriptsQuery());
 
-        selectScriptsStatement = session.prepare(
-            select()
-                .from(CassandraSieveTable.TABLE_NAME)
-                .where(eq(CassandraSieveTable.USER_NAME, 
bindMarker(CassandraSieveTable.USER_NAME))));
-
-        selectScriptStatement = 
session.prepare(getScriptQuery(CassandraSieveTable.SCRIPT_CONTENT, 
CassandraSieveTable.IS_ACTIVE)
-            .and(eq(CassandraSieveTable.SCRIPT_NAME, 
bindMarker(CassandraSieveTable.SCRIPT_NAME))));
-
-        selectScriptMetadataStatement = 
session.prepare(getScriptQuery(CassandraSieveTable.SIZE, 
CassandraSieveTable.IS_ACTIVE, CassandraSieveTable.DATE)
-            .and(eq(CassandraSieveTable.SCRIPT_NAME, 
bindMarker(CassandraSieveTable.SCRIPT_NAME))));
+        selectScriptStatement = session.prepare(getScriptsQuery()
+            .and(eq(SCRIPT_NAME, bindMarker(SCRIPT_NAME))));
 
         updateScriptActivationStatement = session.prepare(
-            update(CassandraSieveTable.TABLE_NAME)
-                .with(set(CassandraSieveTable.IS_ACTIVE, 
bindMarker(CassandraSieveTable.IS_ACTIVE)))
-                .where(eq(CassandraSieveTable.USER_NAME, 
bindMarker(CassandraSieveTable.USER_NAME)))
-                .and(eq(CassandraSieveTable.SCRIPT_NAME, 
bindMarker(CassandraSieveTable.SCRIPT_NAME)))
+            update(TABLE_NAME)
+                .with(set(IS_ACTIVE, bindMarker(IS_ACTIVE)))
+                .where(eq(USER_NAME, bindMarker(USER_NAME)))
+                .and(eq(SCRIPT_NAME, bindMarker(SCRIPT_NAME)))
                 .ifExists());
 
         deleteScriptStatement = session.prepare(
             delete()
-                .from(CassandraSieveTable.TABLE_NAME)
-                .where(eq(CassandraSieveTable.USER_NAME, 
bindMarker(CassandraSieveTable.USER_NAME)))
-                .and(eq(CassandraSieveTable.SCRIPT_NAME, 
bindMarker(CassandraSieveTable.SCRIPT_NAME)))
+                .from(TABLE_NAME)
+                .where(eq(USER_NAME, bindMarker(USER_NAME)))
+                .and(eq(SCRIPT_NAME, bindMarker(SCRIPT_NAME)))
                 .ifExists());
     }
 
-    private Select.Where getScriptQuery(String... selectedRows) {
-        return select(selectedRows)
-            .from(CassandraSieveTable.TABLE_NAME)
-            .where(eq(CassandraSieveTable.USER_NAME, 
bindMarker(CassandraSieveTable.USER_NAME)));
+    private Select.Where getScriptsQuery() {
+        return select(SCRIPT_CONTENT, IS_ACTIVE, SCRIPT_NAME, SIZE)
+            .from(TABLE_NAME)
+            .where(eq(USER_NAME, bindMarker(USER_NAME)));
     }
 
-    public CompletableFuture<Void> insertScript(String user, String name, 
String content, boolean isActive) {
+    public CompletableFuture<Void> insertScript(String user, Script script) {
         return cassandraAsyncExecutor.executeVoid(
             insertScriptStatement.bind()
-                .setString(CassandraSieveTable.USER_NAME, user)
-                .setString(CassandraSieveTable.SCRIPT_NAME, name)
-                .setString(CassandraSieveTable.SCRIPT_CONTENT, content)
-                .setBool(CassandraSieveTable.IS_ACTIVE, isActive)
-                .setLong(CassandraSieveTable.SIZE, content.getBytes().length)
-                .setDate(CassandraSieveTable.DATE, new Date()));
+                .setString(USER_NAME, user)
+                .setString(SCRIPT_NAME, script.getName())
+                .setString(SCRIPT_CONTENT, script.getContent())
+                .setBool(IS_ACTIVE, script.isActive())
+                .setLong(SIZE, script.getSize()));
     }
 
     public CompletableFuture<List<ScriptSummary>> listScripts(String user) {
         return cassandraAsyncExecutor.execute(
             selectScriptsStatement.bind()
-                .setString(CassandraSieveTable.USER_NAME, user))
+                .setString(USER_NAME, user))
             .thenApply(resultSet -> resultSet.all()
                 .stream()
                 .map(row -> new ScriptSummary(
-                    row.getString(CassandraSieveTable.SCRIPT_NAME),
-                    row.getBool(CassandraSieveTable.IS_ACTIVE)))
+                    row.getString(SCRIPT_NAME),
+                    row.getBool(IS_ACTIVE)))
                 .collect(Collectors.toList()));
     }
 
     public CompletableFuture<Boolean> updateScriptActivation(String user, 
String scriptName, boolean active) {
         return cassandraAsyncExecutor.executeReturnApplied(
             updateScriptActivationStatement.bind()
-                .setString(CassandraSieveTable.USER_NAME, user)
-                .setString(CassandraSieveTable.SCRIPT_NAME, scriptName)
-                .setBool(CassandraSieveTable.IS_ACTIVE, active));
-    }
-
-    public CompletableFuture<Optional<ScriptContentAndActivation>> 
getScriptContentAndActivation(String user, String name) {
-        return getScriptRow(user, name).thenApply(opt -> opt.map(row -> new 
ScriptContentAndActivation(
-            row.getString(CassandraSieveTable.SCRIPT_CONTENT),
-            row.getBool(CassandraSieveTable.IS_ACTIVE))));
-    }
-
-    public CompletableFuture<Optional<String>> getScriptContent(String user, 
String name) {
-        return getScriptRow(user, name).thenApply(opt -> opt.map(row -> 
row.getString(CassandraSieveTable.SCRIPT_CONTENT)));
-    }
-
-    public CompletableFuture<Optional<Long>> getScriptSize(String user, String 
name) {
-        return cassandraAsyncExecutor.executeSingleRow(
-            selectScriptMetadataStatement.bind()
-                .setString(CassandraSieveTable.USER_NAME, user)
-                .setString(CassandraSieveTable.SCRIPT_NAME, name))
-            .thenApply(rowOptional -> rowOptional.map(row -> 
row.getLong(CassandraSieveTable.SIZE)));
+                .setString(USER_NAME, user)
+                .setString(SCRIPT_NAME, scriptName)
+                .setBool(IS_ACTIVE, active));
     }
 
-    public CompletableFuture<Optional<DateTime>> 
getActiveScriptActivationDate(String user) {
-        return cassandraAsyncExecutor.executeSingleRow(
-            selectActiveScriptMetadataStatement.bind()
-                .setString(CassandraSieveTable.USER_NAME, user)
-                .setBool(CassandraSieveTable.IS_ACTIVE, true))
-            .thenApply(rowOptional -> rowOptional.map(row -> new 
DateTime(row.getDate(CassandraSieveTable.DATE).getTime())));
+    public CompletableFuture<Optional<Script>> getScript(String user, String 
name) {
+        return getScriptRow(user, name).thenApply(opt -> opt.map(row -> 
Script.builder()
+                .content(row.getString(SCRIPT_CONTENT))
+                .isActive(row.getBool(IS_ACTIVE))
+                .name(name)
+                .size(row.getLong(SIZE))
+                .build()));
     }
 
     public CompletableFuture<Boolean> deleteScriptInCassandra(String user, 
String name) {
         return cassandraAsyncExecutor.executeReturnApplied(
             deleteScriptStatement.bind()
-                .setString(CassandraSieveTable.USER_NAME, user)
-                .setString(CassandraSieveTable.SCRIPT_NAME, name));
-    }
-
-    public CompletableFuture<Boolean> scriptExists(String user, String name) {
-        return getScriptSize(user, name).thenApply(Optional::isPresent);
-    }
-
-
-    public CompletableFuture<Optional<String>> getActiveName(String user) {
-        return cassandraAsyncExecutor.executeSingleRow(
-            selectActiveScriptNameStatement.bind()
-                .setString(CassandraSieveTable.USER_NAME, user)
-                .setBool(CassandraSieveTable.IS_ACTIVE, true))
-            .thenApply(optional -> optional.map(row -> 
row.getString(CassandraSieveTable.SCRIPT_NAME)));
-    }
-
-    public CompletableFuture<Optional<String>> getActive(String user) {
-        return cassandraAsyncExecutor.executeSingleRow(
-            selectActiveScriptStatement.bind()
-                .setString(CassandraSieveTable.USER_NAME, user)
-                .setBool(CassandraSieveTable.IS_ACTIVE, true))
-            .thenApply(rowOptional -> rowOptional.map(row -> 
row.getString(CassandraSieveTable.SCRIPT_CONTENT)));
+                .setString(USER_NAME, user)
+                .setString(SCRIPT_NAME, name));
     }
 
     private CompletableFuture<Optional<Row>> getScriptRow(String user, String 
name) {
         return cassandraAsyncExecutor.executeSingleRow(
             selectScriptStatement.bind()
-                .setString(CassandraSieveTable.USER_NAME, user)
-                .setString(CassandraSieveTable.SCRIPT_NAME, name));
+                .setString(USER_NAME, user)
+                .setString(SCRIPT_NAME, name));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
index 0dd3153..1e3ad9f 100644
--- 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
+++ 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepository.java
@@ -28,9 +28,10 @@ import java.util.concurrent.CompletableFuture;
 import javax.inject.Inject;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.james.sieve.cassandra.model.ScriptContentAndActivation;
-import org.apache.james.sieverepository.api.ScriptSummary;
+import org.apache.james.sieve.cassandra.model.ActiveScriptInfo;
+import org.apache.james.sieve.cassandra.model.Script;
 import org.apache.james.sieve.cassandra.model.SieveQuota;
+import org.apache.james.sieverepository.api.ScriptSummary;
 import org.apache.james.sieverepository.api.SieveRepository;
 import org.apache.james.sieverepository.api.exception.DuplicateException;
 import org.apache.james.sieverepository.api.exception.IsActiveException;
@@ -38,24 +39,28 @@ import 
org.apache.james.sieverepository.api.exception.QuotaExceededException;
 import org.apache.james.sieverepository.api.exception.QuotaNotFoundException;
 import org.apache.james.sieverepository.api.exception.ScriptNotFoundException;
 import org.apache.james.sieverepository.api.exception.StorageException;
+import org.apache.james.util.CompletableFutureUtil;
+import org.apache.james.util.FluentFutureStream;
 import org.joda.time.DateTime;
 
 public class CassandraSieveRepository implements SieveRepository {
 
     private final CassandraSieveDAO cassandraSieveDAO;
     private final CassandraSieveQuotaDAO cassandraSieveQuotaDAO;
+    private final CassandraActiveScriptDAO cassandraActiveScriptDAO;
 
     @Inject
-    public CassandraSieveRepository(CassandraSieveDAO cassandraSieveDAO, 
CassandraSieveQuotaDAO cassandraSieveQuotaDAO) {
+    public CassandraSieveRepository(CassandraSieveDAO cassandraSieveDAO, 
CassandraSieveQuotaDAO cassandraSieveQuotaDAO, CassandraActiveScriptDAO 
cassandraActiveScriptDAO) {
         this.cassandraSieveDAO = cassandraSieveDAO;
         this.cassandraSieveQuotaDAO = cassandraSieveQuotaDAO;
+        this.cassandraActiveScriptDAO = cassandraActiveScriptDAO;
     }
 
     @Override
     public DateTime getActivationDateForActiveScript(String user) throws 
StorageException, ScriptNotFoundException {
-        return cassandraSieveDAO.getActiveScriptActivationDate(user)
-            .join()
-            .orElseThrow(ScriptNotFoundException::new);
+        return cassandraActiveScriptDAO.getActiveSctiptInfo(user).join()
+            .orElseThrow(ScriptNotFoundException::new)
+            .getActivationDate();
     }
 
     @Override
@@ -72,8 +77,9 @@ public class CassandraSieveRepository implements 
SieveRepository {
     }
 
     public CompletableFuture<Long> spaceThatWillBeUsedByNewScript(String user, 
String name, long scriptSize) {
-        return cassandraSieveDAO.getScriptSize(user, name)
-            .thenApply(sizeOfStoredScript -> scriptSize - 
sizeOfStoredScript.orElse(0L));
+        return cassandraSieveDAO.getScript(user, name)
+            .thenApply(optional -> optional.map(Script::getSize).orElse(0L))
+            .thenApply(sizeOfStoredScript -> scriptSize - sizeOfStoredScript);
     }
 
     private Optional<Long> limitToUse(CompletableFuture<Optional<Long>> 
userQuota, CompletableFuture<Optional<Long>> globalQuota) {
@@ -90,7 +96,12 @@ public class CassandraSieveRepository implements 
SieveRepository {
 
         CompletableFuture.allOf(
             updateSpaceUsed(user, spaceUsed.join()),
-            cassandraSieveDAO.insertScript(user, name, content, false))
+            cassandraSieveDAO.insertScript(user,
+                Script.builder()
+                    .name(name)
+                    .content(content)
+                    .isActive(false)
+                    .build()))
             .join();
     }
 
@@ -109,15 +120,21 @@ public class CassandraSieveRepository implements 
SieveRepository {
     @Override
     public InputStream getActive(String user) throws ScriptNotFoundException {
         return IOUtils.toInputStream(
-            cassandraSieveDAO.getActive(user)
+            cassandraActiveScriptDAO.getActiveSctiptInfo(user)
+                .thenCompose(optionalActiveName -> optionalActiveName
+                    .map(activeScriptInfo -> cassandraSieveDAO.getScript(user, 
activeScriptInfo.getName()))
+                    
.orElse(CompletableFuture.completedFuture(Optional.empty())))
                 .join()
-                .orElseThrow(ScriptNotFoundException::new), 
StandardCharsets.UTF_8);
+                .orElseThrow(ScriptNotFoundException::new)
+                .getContent(), StandardCharsets.UTF_8);
     }
 
     @Override
     public void setActive(String user, String name) throws 
ScriptNotFoundException {
         CompletableFuture<Void> unactivateOldScriptFuture = 
unactivateOldScript(user);
-        CompletableFuture<Boolean> activateNewScript = 
updateScriptActivation(user, name, true);
+        CompletableFuture<Boolean> activateNewScript = 
updateScriptActivation(user, name, true)
+            .thenCompose(CompletableFutureUtil.composeIfTrue(
+                () -> cassandraActiveScriptDAO.activate(user, name)));
 
         unactivateOldScriptFuture.join();
         if (!activateNewScript.join()) {
@@ -126,9 +143,9 @@ public class CassandraSieveRepository implements 
SieveRepository {
     }
 
     private CompletableFuture<Void> unactivateOldScript(String user) {
-        return cassandraSieveDAO.getActiveName(user)
+        return cassandraActiveScriptDAO.getActiveSctiptInfo(user)
             .thenCompose(scriptNameOptional -> scriptNameOptional
-                .map(scriptName -> updateScriptActivation(user, scriptName, 
false)
+                .map(activeScriptInfo -> updateScriptActivation(user, 
activeScriptInfo.getName(), false)
                     .<Void>thenApply(any -> null))
                 .orElse(CompletableFuture.completedFuture(null)));
     }
@@ -137,14 +154,14 @@ public class CassandraSieveRepository implements 
SieveRepository {
         if (!scriptName.equals(SieveRepository.NO_SCRIPT_NAME)) {
             return cassandraSieveDAO.updateScriptActivation(user, scriptName, 
active);
         }
-        return CompletableFuture.completedFuture(true);
+        return cassandraActiveScriptDAO.unactivate(user).thenApply(any -> 
true);
     }
 
     @Override
     public InputStream getScript(String user, String name) throws 
ScriptNotFoundException {
-        return  cassandraSieveDAO.getScriptContent(user, name)
+        return  cassandraSieveDAO.getScript(user, name)
             .join()
-            .map(script -> IOUtils.toInputStream(script, 
StandardCharsets.UTF_8))
+            .map(script -> IOUtils.toInputStream(script.getContent(), 
StandardCharsets.UTF_8))
             .orElseThrow(ScriptNotFoundException::new);
     }
 
@@ -157,7 +174,7 @@ public class CassandraSieveRepository implements 
SieveRepository {
     }
 
     private void ensureIsNotActive(String user, String name) throws 
IsActiveException {
-        Optional<String> activeName = 
cassandraSieveDAO.getActiveName(user).join();
+        Optional<String> activeName = 
cassandraActiveScriptDAO.getActiveSctiptInfo(user).join().map(ActiveScriptInfo::getName);
         if (activeName.isPresent() && name.equals(activeName.get())) {
             throw new IsActiveException();
         }
@@ -165,8 +182,9 @@ public class CassandraSieveRepository implements 
SieveRepository {
 
     @Override
     public void renameScript(String user, String oldName, String newName) 
throws ScriptNotFoundException, DuplicateException {
-        CompletableFuture<Boolean> scriptExistsFuture = 
cassandraSieveDAO.scriptExists(user, newName);
-        CompletableFuture<Optional<ScriptContentAndActivation>> 
oldScriptFuture = cassandraSieveDAO.getScriptContentAndActivation(user, 
oldName);
+        CompletableFuture<Boolean> scriptExistsFuture = 
cassandraSieveDAO.getScript(user, newName)
+            .thenApply(Optional::isPresent);
+        CompletableFuture<Optional<Script>> oldScriptFuture = 
cassandraSieveDAO.getScript(user, oldName);
 
         oldScriptFuture.join();
         if (scriptExistsFuture.join()) {
@@ -174,18 +192,30 @@ public class CassandraSieveRepository implements 
SieveRepository {
         }
 
         performScriptRename(user,
-            oldName,
             newName,
             oldScriptFuture.join().orElseThrow(ScriptNotFoundException::new));
     }
 
-    private void performScriptRename(String user, String oldName, String 
newName, ScriptContentAndActivation oldScript) {
+    private void performScriptRename(String user, String newName, Script 
oldScript) {
         CompletableFuture.allOf(
-            cassandraSieveDAO.insertScript(user, newName, 
oldScript.getContent(), oldScript.isActive()),
-            cassandraSieveDAO.deleteScriptInCassandra(user, oldName))
+            cassandraSieveDAO.insertScript(user,
+                Script.builder()
+                    .copyOf(oldScript)
+                    .name(newName)
+                    .build()),
+            cassandraSieveDAO.deleteScriptInCassandra(user, 
oldScript.getName()),
+            performActiveScriptRename(user, oldScript.getName(), newName))
             .join();
     }
 
+    private CompletableFuture<Void> performActiveScriptRename(String user, 
String oldName, String newName) {
+        return cassandraActiveScriptDAO.getActiveSctiptInfo(user)
+            .thenCompose(optionalActivationInfo -> optionalActivationInfo
+                .filter(activeScriptInfo -> 
activeScriptInfo.getName().equals(oldName))
+                .map(name -> cassandraActiveScriptDAO.activate(user, newName))
+                .orElse(CompletableFuture.completedFuture(null)));
+    }
+
     @Override
     public boolean hasQuota() {
         return cassandraSieveQuotaDAO.getQuota()
@@ -214,11 +244,12 @@ public class CassandraSieveRepository implements 
SieveRepository {
 
     @Override
     public boolean hasQuota(String user) {
-        CompletableFuture<Boolean> userQuotaIsPresent = 
cassandraSieveQuotaDAO.getQuota(user).thenApply(Optional::isPresent);
-        CompletableFuture<Boolean> globalQuotaIsPresent = 
cassandraSieveQuotaDAO.getQuota().thenApply(Optional::isPresent);
-        CompletableFuture.allOf(userQuotaIsPresent, 
globalQuotaIsPresent).join();
-
-        return userQuotaIsPresent.join() || globalQuotaIsPresent.join();
+        return FluentFutureStream.ofFutures(
+                
cassandraSieveQuotaDAO.getQuota(user).thenApply(Optional::isPresent),
+                
cassandraSieveQuotaDAO.getQuota().thenApply(Optional::isPresent))
+            .reduce((b1, b2) -> b1 || b2)
+            .thenApply(Optional::get)
+            .join();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryModule.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryModule.java
 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryModule.java
index c59053d..b837030 100644
--- 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryModule.java
+++ 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryModule.java
@@ -31,6 +31,7 @@ import 
org.apache.james.backends.cassandra.components.CassandraIndex;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.components.CassandraTable;
 import org.apache.james.backends.cassandra.components.CassandraType;
+import org.apache.james.sieve.cassandra.tables.CassandraSieveActiveTable;
 import org.apache.james.sieve.cassandra.tables.CassandraSieveClusterQuotaTable;
 import org.apache.james.sieve.cassandra.tables.CassandraSieveQuotaTable;
 import org.apache.james.sieve.cassandra.tables.CassandraSieveSpaceTable;
@@ -54,7 +55,6 @@ public class CassandraSieveRepositoryModule implements 
CassandraModule {
                     .addClusteringColumn(CassandraSieveTable.SCRIPT_NAME, 
text())
                     .addColumn(CassandraSieveTable.SCRIPT_CONTENT, text())
                     .addColumn(CassandraSieveTable.IS_ACTIVE, cboolean())
-                    .addColumn(CassandraSieveTable.DATE, timestamp())
                     .addColumn(CassandraSieveTable.SIZE, bigint())),
             new CassandraTable(CassandraSieveSpaceTable.TABLE_NAME,
                 SchemaBuilder.createTable(CassandraSieveSpaceTable.TABLE_NAME)
@@ -70,13 +70,14 @@ public class CassandraSieveRepositoryModule implements 
CassandraModule {
                 
SchemaBuilder.createTable(CassandraSieveClusterQuotaTable.TABLE_NAME)
                     .ifNotExists()
                     .addPartitionKey(CassandraSieveClusterQuotaTable.NAME, 
text())
-                    .addColumn(CassandraSieveClusterQuotaTable.VALUE, 
bigint())));
-        index = ImmutableList.of(
-            new CassandraIndex(
-                SchemaBuilder.createIndex(CassandraIndex.INDEX_PREFIX + 
CassandraSieveTable.TABLE_NAME + CassandraSieveTable.IS_ACTIVE)
+                    .addColumn(CassandraSieveClusterQuotaTable.VALUE, 
bigint())),
+            new CassandraTable(CassandraSieveActiveTable.TABLE_NAME,
+                SchemaBuilder.createTable(CassandraSieveActiveTable.TABLE_NAME)
                     .ifNotExists()
-                    .onTable(CassandraSieveTable.TABLE_NAME)
-                    .andColumn(CassandraSieveTable.IS_ACTIVE)));
+                    .addPartitionKey(CassandraSieveActiveTable.USER_NAME, 
text())
+                    .addColumn(CassandraSieveActiveTable.SCRIPT_NAME, text())
+                    .addColumn(CassandraSieveActiveTable.DATE, timestamp())));
+        index = ImmutableList.of();
         types = ImmutableList.of();
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ActiveScriptInfo.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ActiveScriptInfo.java
 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ActiveScriptInfo.java
new file mode 100644
index 0000000..b3377be
--- /dev/null
+++ 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ActiveScriptInfo.java
@@ -0,0 +1,43 @@
+/****************************************************************
+ * 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.sieve.cassandra.model;
+
+import java.util.Date;
+
+import org.joda.time.DateTime;
+
+public class ActiveScriptInfo {
+
+    private final String name;
+    private final DateTime activationDate;
+
+    public ActiveScriptInfo(String content, Date date) {
+        this.name = content;
+        this.activationDate = new DateTime(date);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public DateTime getActivationDate() {
+        return activationDate;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ScriptContentAndActivation.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ScriptContentAndActivation.java
 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ScriptContentAndActivation.java
deleted file mode 100644
index 0e26b7b..0000000
--- 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/model/ScriptContentAndActivation.java
+++ /dev/null
@@ -1,39 +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.sieve.cassandra.model;
-
-public class ScriptContentAndActivation {
-
-    private final String content;
-    private final boolean activation;
-
-    public ScriptContentAndActivation(String content, boolean activation) {
-        this.content = content;
-        this.activation = activation;
-    }
-
-    public String getContent() {
-        return content;
-    }
-
-    public boolean isActive() {
-        return activation;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveActiveTable.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveActiveTable.java
 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveActiveTable.java
new file mode 100644
index 0000000..efc64d0
--- /dev/null
+++ 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveActiveTable.java
@@ -0,0 +1,30 @@
+/****************************************************************
+ * 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.sieve.cassandra.tables;
+
+public interface CassandraSieveActiveTable {
+
+    String TABLE_NAME = "sieve_active";
+
+    String USER_NAME = "user_name";
+    String SCRIPT_NAME = "script_name";
+    String DATE = "date";
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveTable.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveTable.java
 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveTable.java
index 9479ea3..c247352 100644
--- 
a/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveTable.java
+++ 
b/server/data/data-cassandra/src/main/java/org/apache/james/sieve/cassandra/tables/CassandraSieveTable.java
@@ -26,6 +26,5 @@ public interface CassandraSieveTable {
     String SCRIPT_NAME = "script_name";
     String SCRIPT_CONTENT = "script_content";
     String IS_ACTIVE = "is_active";
-    String DATE = "date";
     String SIZE = "size";
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java
 
b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java
new file mode 100644
index 0000000..efdfa14
--- /dev/null
+++ 
b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraActiveScriptDAOTest.java
@@ -0,0 +1,97 @@
+/****************************************************************
+ * 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.sieve.cassandra;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Optional;
+
+import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.sieve.cassandra.model.ActiveScriptInfo;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CassandraActiveScriptDAOTest {
+
+    public static final String USER = "user";
+    public static final String SCRIPT_NAME = "sciptName";
+    public static final String NEW_SCRIPT_NAME = "newScriptName";
+    private static CassandraCluster cassandra = CassandraCluster.create(new 
CassandraSieveRepositoryModule());
+    private CassandraActiveScriptDAO activeScriptDAO;
+
+    @Before
+    public void setUp() {
+        cassandra.ensureAllTables();
+        activeScriptDAO = new CassandraActiveScriptDAO(cassandra.getConf());
+    }
+
+    @After
+    public void tearDown() {
+        cassandra.clearAllTables();
+    }
+
+    @Test
+    public void getActiveSctiptInfoShouldReturnEmptyByDefault() {
+        
assertThat(activeScriptDAO.getActiveSctiptInfo(USER).join().isPresent())
+            .isFalse();
+    }
+
+    @Test
+    public void getActiveSctiptInfoShouldReturnStoredName() {
+        activeScriptDAO.activate(USER, SCRIPT_NAME).join();
+
+        Optional<ActiveScriptInfo> actual = 
activeScriptDAO.getActiveSctiptInfo(USER).join();
+
+        assertThat(actual.isPresent()).isTrue();
+        assertThat(actual.get().getName()).isEqualTo(SCRIPT_NAME);
+    }
+
+    @Test
+    public void activateShouldAllowRename() {
+        activeScriptDAO.activate(USER, SCRIPT_NAME).join();
+
+        activeScriptDAO.activate(USER, NEW_SCRIPT_NAME).join();
+
+        Optional<ActiveScriptInfo> actual = 
activeScriptDAO.getActiveSctiptInfo(USER).join();
+        assertThat(actual.isPresent()).isTrue();
+        assertThat(actual.get().getName()).isEqualTo(NEW_SCRIPT_NAME);
+    }
+
+    @Test
+    public void unactivateShouldAllowRemovingActiveScript() {
+        activeScriptDAO.activate(USER, SCRIPT_NAME).join();
+
+        activeScriptDAO.unactivate(USER).join();
+
+        Optional<ActiveScriptInfo> actual = 
activeScriptDAO.getActiveSctiptInfo(USER).join();
+        assertThat(actual.isPresent()).isFalse();
+    }
+
+
+    @Test
+    public void unactivateShouldWorkWhenNoneStore() {
+        activeScriptDAO.unactivate(USER).join();
+
+        Optional<ActiveScriptInfo> actual = 
activeScriptDAO.getActiveSctiptInfo(USER).join();
+        assertThat(actual.isPresent()).isFalse();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
 
b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
new file mode 100644
index 0000000..243279b
--- /dev/null
+++ 
b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveDAOTest.java
@@ -0,0 +1,143 @@
+/****************************************************************
+ * 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.sieve.cassandra;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.sieve.cassandra.model.Script;
+import org.apache.james.sieverepository.api.ScriptSummary;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CassandraSieveDAOTest {
+
+    public static final String USER = "user";
+    public static final String SCRIPT_NAME = "scriptName";
+    public static final String SCRIPT_NAME2 = "scriptName2";
+    public static final Script SCRIPT = Script.builder()
+        .name(SCRIPT_NAME)
+        .content("content")
+        .isActive(false)
+        .build();
+    public static final Script SCRIPT2 = Script.builder()
+        .name(SCRIPT_NAME2)
+        .content("alternative content")
+        .isActive(true)
+        .build();
+    public static final Script ACTIVE_SCRIPT = Script.builder()
+        .copyOf(SCRIPT)
+        .isActive(true)
+        .build();
+    public static final Script SCRIPT_NEW_CONTENT = Script.builder()
+        .copyOf(SCRIPT)
+        .content("newContent")
+        .build();
+    private static CassandraCluster cassandra = CassandraCluster.create(new 
CassandraSieveRepositoryModule());
+    private CassandraSieveDAO sieveDAO;
+
+    @Before
+    public void setUp() {
+        cassandra.ensureAllTables();
+        sieveDAO = new CassandraSieveDAO(cassandra.getConf());
+    }
+
+    @After
+    public void tearDown() {
+        cassandra.clearAllTables();
+    }
+
+    @Test
+    public void getScriptShouldReturnEmptyByDefault() {
+        assertThat(sieveDAO.getScript(USER, SCRIPT_NAME).join().isPresent())
+            .isFalse();
+    }
+
+    @Test
+    public void getScriptShouldReturnStoredScript() {
+        sieveDAO.insertScript(USER, SCRIPT).join();
+
+        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join();
+
+        assertThat(actual.isPresent()).isTrue();
+        assertThat(actual.get()).isEqualTo(SCRIPT);
+    }
+
+    @Test
+    public void insertScriptShouldUpdateContent() {
+        sieveDAO.insertScript(USER, SCRIPT).join();
+
+        sieveDAO.insertScript(USER, SCRIPT_NEW_CONTENT).join();
+
+        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join();
+        assertThat(actual.isPresent()).isTrue();
+        assertThat(actual.get()).isEqualTo(SCRIPT_NEW_CONTENT);
+    }
+
+    @Test
+    public void insertScriptShouldUpdateActivate() {
+        sieveDAO.insertScript(USER, SCRIPT).join();
+
+        sieveDAO.insertScript(USER, ACTIVE_SCRIPT).join();
+
+        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join();
+        assertThat(actual.isPresent()).isTrue();
+        assertThat(actual.get()).isEqualTo(ACTIVE_SCRIPT);
+    }
+
+    @Test
+    public void deleteScriptInCassandraShouldWork() {
+        sieveDAO.insertScript(USER, SCRIPT).join();
+
+        sieveDAO.deleteScriptInCassandra(USER, SCRIPT_NAME).join();
+
+        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join();
+        assertThat(actual.isPresent()).isFalse();
+    }
+
+    @Test
+    public void deleteScriptInCassandraShouldWorkWhenNoneStore() {
+        sieveDAO.deleteScriptInCassandra(USER, SCRIPT_NAME).join();
+
+        Optional<Script> actual = sieveDAO.getScript(USER, SCRIPT_NAME).join();
+        assertThat(actual.isPresent()).isFalse();
+    }
+
+    @Test
+    public void listScriptsShouldReturnEmpty() {
+        List<ScriptSummary> scriptSummaryList = 
sieveDAO.listScripts(USER).join();
+
+        assertThat(scriptSummaryList).isEmpty();
+    }
+
+    @Test
+    public void listScriptsShouldReturnSingleStoredValue() {
+        sieveDAO.insertScript(USER, SCRIPT).join();
+        sieveDAO.insertScript(USER, SCRIPT2).join();
+
+        List<ScriptSummary> scriptSummaryList = 
sieveDAO.listScripts(USER).join();
+
+        assertThat(scriptSummaryList).containsOnly(SCRIPT.toSummary(), 
SCRIPT2.toSummary());
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
 
b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
new file mode 100644
index 0000000..51ae3ed
--- /dev/null
+++ 
b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveQuotaDAOTest.java
@@ -0,0 +1,149 @@
+/****************************************************************
+ * 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.sieve.cassandra;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Optional;
+
+import org.apache.james.backends.cassandra.CassandraCluster;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CassandraSieveQuotaDAOTest {
+
+    public static final String USER = "user";
+    private static CassandraCluster cassandra = CassandraCluster.create(new 
CassandraSieveRepositoryModule());
+    private CassandraSieveQuotaDAO sieveQuotaDAO;
+
+    @Before
+    public void setUp() {
+        cassandra.ensureAllTables();
+        sieveQuotaDAO = new CassandraSieveQuotaDAO(cassandra.getConf());
+    }
+
+    @After
+    public void tearDown() {
+        cassandra.clearAllTables();
+    }
+
+    @Test
+    public void getQuotaShouldReturnEmptyByDefault() {
+        assertThat(sieveQuotaDAO.getQuota().join().isPresent())
+            .isFalse();
+    }
+
+    @Test
+    public void getQuotaUserShouldReturnEmptyByDefault() {
+        assertThat(sieveQuotaDAO.getQuota(USER).join().isPresent())
+            .isFalse();
+    }
+
+    @Test
+    public void getQuotaShouldReturnStoredValue() {
+        long quota = 15L;
+        sieveQuotaDAO.setQuota(quota).join();
+
+        Optional<Long> actual = sieveQuotaDAO.getQuota().join();
+        assertThat(actual.isPresent()).isTrue();
+        assertThat(actual.get()).isEqualTo(quota);
+    }
+
+    @Test
+    public void getQuotaUserShouldReturnStoredValue() {
+        long quota = 15L;
+        sieveQuotaDAO.setQuota(USER, quota).join();
+
+        Optional<Long> actual = sieveQuotaDAO.getQuota(USER).join();
+        assertThat(actual.isPresent()).isTrue();
+        assertThat(actual.get()).isEqualTo(quota);
+    }
+
+    @Test
+    public void removeQuotaShouldDeleteQuota() {
+        sieveQuotaDAO.setQuota(15L).join();
+
+        sieveQuotaDAO.removeQuota().join();
+
+        Optional<Long> actual = sieveQuotaDAO.getQuota().join();
+        assertThat(actual.isPresent()).isFalse();
+    }
+
+    @Test
+    public void removeQuotaUserShouldDeleteQuotaUser() {
+        sieveQuotaDAO.setQuota(USER, 15L).join();
+
+        sieveQuotaDAO.removeQuota(USER).join();
+
+        Optional<Long> actual = sieveQuotaDAO.getQuota(USER).join();
+        assertThat(actual.isPresent()).isFalse();
+    }
+
+    @Test
+    public void removeQuotaShouldWorkWhenNoneStore() {
+        sieveQuotaDAO.removeQuota().join();
+
+        Optional<Long> actual = sieveQuotaDAO.getQuota().join();
+        assertThat(actual.isPresent()).isFalse();
+    }
+
+    @Test
+    public void removeQuotaUserShouldWorkWhenNoneStore() {
+        sieveQuotaDAO.removeQuota(USER).join();
+
+        Optional<Long> actual = sieveQuotaDAO.getQuota(USER).join();
+        assertThat(actual.isPresent()).isFalse();
+    }
+
+    @Test
+    public void spaceUsedByShouldReturnZeroByDefault() {
+        assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(0);
+    }
+
+    @Test
+    public void spaceUsedByShouldReturnStoredValue() {
+        long spaceUsed = 18L;
+
+        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join();
+
+        
assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(spaceUsed);
+    }
+
+    @Test
+    public void updateSpaceUsedShouldBeAdditive() {
+        long spaceUsed = 18L;
+
+        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join();
+        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join();
+
+        assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(2 * 
spaceUsed);
+    }
+
+    @Test
+    public void updateSpaceUsedShouldWorkWithNegativeValues() {
+        long spaceUsed = 18L;
+
+        sieveQuotaDAO.updateSpaceUsed(USER, spaceUsed).join();
+        sieveQuotaDAO.updateSpaceUsed(USER, -1 * spaceUsed).join();
+
+        assertThat(sieveQuotaDAO.spaceUsedBy(USER).join()).isEqualTo(0L);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/f28cc423/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryTest.java
----------------------------------------------------------------------
diff --git 
a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryTest.java
 
b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryTest.java
index bf1fd34..8451207 100644
--- 
a/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryTest.java
+++ 
b/server/data/data-cassandra/src/test/java/org/apache/james/sieve/cassandra/CassandraSieveRepositoryTest.java
@@ -19,65 +19,23 @@
 
 package org.apache.james.sieve.cassandra;
 
-import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.Date;
-
 import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.sieve.cassandra.tables.CassandraSieveTable;
 import org.apache.james.sieverepository.api.SieveRepository;
-import org.apache.james.sieverepository.api.exception.ScriptNotFoundException;
 import org.apache.james.sieverepository.lib.AbstractSieveRepositoryTest;
-import org.joda.time.DateTime;
-import org.junit.Test;
 
 public class CassandraSieveRepositoryTest extends AbstractSieveRepositoryTest {
-    public static final int DATE_TIMESTAMP = 123456141;
-    private CassandraCluster cassandra;
-
-    public CassandraSieveRepositoryTest() {
-        cassandra = CassandraCluster.create(new 
CassandraSieveRepositoryModule());
-    }
+    private CassandraCluster cassandra = CassandraCluster.create(new 
CassandraSieveRepositoryModule());
 
     @Override
     protected SieveRepository createSieveRepository() throws Exception {
         return new CassandraSieveRepository(
             new CassandraSieveDAO(cassandra.getConf()),
-            new CassandraSieveQuotaDAO(cassandra.getConf()));
+            new CassandraSieveQuotaDAO(cassandra.getConf()),
+            new CassandraActiveScriptDAO(cassandra.getConf()));
     }
 
     @Override
     protected void cleanUp() throws Exception {
         cassandra.clearAllTables();
     }
-
-    @Test
-    public void getActivationDateForActiveScriptShouldWork() throws Exception {
-        cassandra.getConf().execute(
-            insertInto(CassandraSieveTable.TABLE_NAME)
-                .value(CassandraSieveTable.USER_NAME, USER)
-                .value(CassandraSieveTable.SCRIPT_NAME, SCRIPT_NAME)
-                .value(CassandraSieveTable.SCRIPT_CONTENT, SCRIPT_CONTENT)
-                .value(CassandraSieveTable.IS_ACTIVE, true)
-                .value(CassandraSieveTable.SIZE, SCRIPT_CONTENT.length())
-                .value(CassandraSieveTable.DATE, new Date(DATE_TIMESTAMP))
-        );
-        
assertThat(sieveRepository.getActivationDateForActiveScript(USER)).isEqualTo(new
 DateTime(DATE_TIMESTAMP));
-    }
-
-
-    @Test(expected = ScriptNotFoundException.class)
-    public void 
getActivationDateForActiveScriptShouldThrowOnMissingActiveScript() throws 
Exception {
-        cassandra.getConf().execute(
-            insertInto(CassandraSieveTable.TABLE_NAME)
-                .value(CassandraSieveTable.USER_NAME, USER)
-                .value(CassandraSieveTable.SCRIPT_NAME, SCRIPT_NAME)
-                .value(CassandraSieveTable.SCRIPT_CONTENT, SCRIPT_CONTENT)
-                .value(CassandraSieveTable.IS_ACTIVE, false)
-                .value(CassandraSieveTable.SIZE, SCRIPT_CONTENT.length())
-                .value(CassandraSieveTable.DATE, DATE_TIMESTAMP)
-        );
-        sieveRepository.getActivationDateForActiveScript(USER);
-    }
 }
\ No newline at end of file


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