Hi,

I implemented several improvments for the Cassandra mailbox.

It includes :

 - A CassandraGroupMembershipResolver : a distributed Group Membership
resolver using Cassandra as a backend.

 - ACL support :
   - I overloaded the simplemailbox to store and retrie acl in cassandra
   - I stock those ACL in cassandra in JSon format, so there is an ACL
to JSOn converter using Jackson.

  - A distributed quota management system based on Cassandra. It have
the same architecture than what is done in the store for quota
management, including :
     - A CassandraPerUserQuotaManager : fix quota policies by user
     - A CassandraFixedQuotaManager : fix global quota policies
     - These are based on a CassandraListeningQuotaManager, so thats its
updated for all received e-mail.
     - All these classes uses a CassandraQuotaStorage class to work with
Cassandra, so that storage operations are centralised in a class.



You will find these improvments in the attached patch.

Sincerly yours,

Benoit Tellier
diff -uNr james-mailbox/README.md james-mailbox-new/README.md
--- james-mailbox/README.md	2014-12-17 16:04:47.596753249 +0100
+++ james-mailbox-new/README.md	2014-12-17 17:09:55.650255631 +0100
@@ -13,6 +13,7 @@
 
 ~~~
 |-- api             -- Mailbox API
+|-- cassandra       -- Mailbox implementation over Cassandra
 |-- hbase           -- Mailbox implementation over HBase
 |-- jcr             -- Mailbox implementation over Java Content Repository (JCR)
 |-- jpa             -- Database Mailbox implementation using Java Persistence API
@@ -61,6 +62,15 @@
 * distributed SMTP/IMAP access
 * other
 
+Mailbox Cassandra
+=================
+
+Uses Apache Cassandra (http://cassandra.apache.org/) for storing email messages. Provides a scalable email storage. To have a fully
+distributed email server you will also need, among others:
+
+* distributed SMTP/IMAP access
+* other
+
 Zookeeper Sequence Provider
 ==========================
 
diff -uNr james-mailbox/cassandra/pom.xml james-mailbox-new/cassandra/pom.xml
--- james-mailbox/cassandra/pom.xml	2014-12-16 17:49:32.729928977 +0100
+++ james-mailbox-new/cassandra/pom.xml	2014-12-17 17:14:11.796933378 +0100
@@ -70,6 +70,11 @@
 	    <version>${cassandra-driver-core.version}</version>
         </dependency>
         <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.3.3</version>
+        </dependency>
+        <dependency>
     	    <groupId>org.cassandraunit</groupId>
    	    <artifactId>cassandra-unit</artifactId>
             <version>${cassandra-unit.version}</version>
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraGroupMembershipResolver.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraGroupMembershipResolver.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraGroupMembershipResolver.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraGroupMembershipResolver.java	2014-12-17 17:09:55.650255631 +0100
@@ -0,0 +1,78 @@
+/****************************************************************
+ * 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.mailbox.cassandra;
+
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Session;
+import org.apache.james.mailbox.acl.GroupMembershipResolver;
+import org.apache.james.mailbox.cassandra.table.CassandraGroupMembershipTable;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.*;
+
+
+/**
+ * A group membership resolver with data stored in Cassandra
+ */
+public class CassandraGroupMembershipResolver implements GroupMembershipResolver {
+
+    Session session;
+
+    public CassandraGroupMembershipResolver(Session session) {
+        this.session = session;
+    }
+
+    public void addMembership(String group, String user) {
+        session.execute(
+                insertInto(CassandraGroupMembershipTable.TABLE)
+                        .value(CassandraGroupMembershipTable.GROUP, group)
+                        .value(CassandraGroupMembershipTable.USER, user)
+                        .ifNotExists()
+        );
+    }
+
+    public void removeMembership(String group, String user) {
+        session.execute(
+                delete()
+                        .from(CassandraGroupMembershipTable.TABLE)
+                        .where(
+                                eq(CassandraGroupMembershipTable.GROUP, group)
+                        )
+                        .and(
+                                eq(CassandraGroupMembershipTable.USER, user)
+                        )
+        );
+    }
+
+    @Override
+    public boolean isMember(String user, String group) {
+        ResultSet resultSet = session.execute(
+                select(CassandraGroupMembershipTable.USER)
+                        .from(CassandraGroupMembershipTable.TABLE)
+                        .where(
+                                eq(CassandraGroupMembershipTable.USER, user)
+                        )
+                        .and(
+                                eq(CassandraGroupMembershipTable.GROUP, group)
+                        )
+        );
+        return !resultSet.isExhausted();
+    }
+
+
+}
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java	2014-12-16 17:49:32.063262337 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java	2014-12-17 17:14:11.796933378 +0100
@@ -25,13 +25,13 @@
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
 import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
+import org.apache.james.mailbox.cassandra.mail.model.CassandraMailbox;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.store.Authenticator;
 import org.apache.james.mailbox.store.StoreMailboxManager;
 import org.apache.james.mailbox.store.StoreMessageManager;
 import org.apache.james.mailbox.store.mail.model.Mailbox;
-import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
 
 /**
  * Cassandra implementation of {@link StoreMailboxManager}
@@ -46,7 +46,8 @@
 
     @Override
     protected Mailbox<UUID> doCreateMailbox(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
-        return new SimpleMailbox<UUID>(mailboxPath, randomUidValidity());
+        CassandraMailboxSessionMapperFactory cassandraMailboxSessionMapperFactory = (CassandraMailboxSessionMapperFactory)getMapperFactory();
+        return new CassandraMailbox<UUID>(mailboxPath, randomUidValidity(), cassandraMailboxSessionMapperFactory.getSession());
     }
 
     @Override
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java	2014-12-16 17:49:32.073262337 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java	2014-12-17 17:14:11.796933378 +0100
@@ -71,4 +71,8 @@
     public UidProvider<UUID> getUidProvider() {
         return uidProvider;
     }
+
+    Session getSession() {
+        return session;
+    }
 }
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java	2014-12-16 17:49:32.079929004 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java	2014-12-17 17:14:11.796933378 +0100
@@ -27,12 +27,18 @@
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
 import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
+import org.apache.james.mailbox.cassandra.mail.model.CassandraMailbox;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.exception.UnsupportedRightException;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.apache.james.mailbox.model.SimpleMailboxACL;
 import org.apache.james.mailbox.store.MailboxEventDispatcher;
 import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
 import org.apache.james.mailbox.store.StoreMessageManager;
 import org.apache.james.mailbox.store.mail.model.Mailbox;
 import org.apache.james.mailbox.store.search.MessageSearchIndex;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Cassandra implementation of {@link StoreMessageManager}
@@ -40,9 +46,18 @@
  */
 public class CassandraMessageManager extends StoreMessageManager<UUID> {
 
-    public CassandraMessageManager(MailboxSessionMapperFactory<UUID> mapperFactory, MessageSearchIndex<UUID> index, MailboxEventDispatcher<UUID> dispatcher, MailboxPathLocker locker, Mailbox<UUID> mailbox) throws MailboxException {
+    private static final int ACL_MAX_RETRY = 100000;
+
+    private static final Logger LOG = LoggerFactory.getLogger(CassandraMessageManager.class);
+    private int aclMaxRetry;
+
+    public CassandraMessageManager(MailboxSessionMapperFactory<UUID> mapperFactory, MessageSearchIndex<UUID> index, MailboxEventDispatcher<UUID> dispatcher, MailboxPathLocker locker, Mailbox<UUID> mailbox, int aclMaxRetry) throws MailboxException {
         super(mapperFactory, index, dispatcher, locker, mailbox, new UnionMailboxACLResolver(), new SimpleGroupMembershipResolver());
+        this.aclMaxRetry = aclMaxRetry;
+    }
 
+    public CassandraMessageManager(MailboxSessionMapperFactory<UUID> mapperFactory, MessageSearchIndex<UUID> index, MailboxEventDispatcher<UUID> dispatcher, MailboxPathLocker locker, Mailbox<UUID> mailbox) throws MailboxException {
+        this(mapperFactory, index, dispatcher, locker, mailbox, ACL_MAX_RETRY);
     }
 
     /**
@@ -54,4 +69,54 @@
         flags.add(Flags.Flag.USER);
         return flags;
     }
+
+    /**
+     * @throws UnsupportedRightException
+     * @see MessageManager#setRights(MailboxACL.MailboxACLEntryKey, MailboxACL.EditMode, MailboxACL.MailboxACLRights) (String, MailboxACL.EditMode, MailboxACL.MailboxACLRights)
+     */
+    @Override
+    public void setRights(MailboxACL.MailboxACLEntryKey mailboxACLEntryKey, MailboxACL.EditMode editMode, MailboxACL.MailboxACLRights mailboxAclRights) throws UnsupportedRightException {
+        boolean succeeded = false;
+        CassandraMailbox<UUID> cassandraMailbox;
+        try {
+            cassandraMailbox = (CassandraMailbox<UUID>) getMailboxEntity();
+        } catch(MailboxException me) {
+            LOG.error("Can not retrieve mailbox while setting ACLs");
+            return;
+        }
+        int tries = 0;
+        while(!succeeded && tries < aclMaxRetry) {
+            tries++;
+            succeeded = tryToUpdateACL(mailboxACLEntryKey, editMode, mailboxAclRights, cassandraMailbox);
+        }
+        if(!succeeded) {
+            LOG.error("Can not apply lightweight transaction for setting ACL rights on " + cassandraMailbox.getUser() +
+                    ":" + cassandraMailbox.getNamespace() + ":" + cassandraMailbox.getName() + " after " + tries + " tries.");
+        }
+    }
+
+    private boolean tryToUpdateACL(MailboxACL.MailboxACLEntryKey mailboxACLEntryKey, MailboxACL.EditMode editMode, MailboxACL.MailboxACLRights mailboxAclRights, CassandraMailbox<UUID> cassandraMailbox) throws UnsupportedRightException {
+        boolean succeeded;
+        CassandraMailbox<UUID>.ACLWithVersion aclWithVersion = cassandraMailbox.getACLWithVersion();
+        MailboxACL acl = aclWithVersion.acl;
+        if (acl == null ) {
+            acl = SimpleMailboxACL.EMPTY;
+        }
+        acl = manageMailboxACL(mailboxACLEntryKey, editMode, mailboxAclRights, acl);
+        succeeded = cassandraMailbox.setACLWithVersion(acl, aclWithVersion.version);
+        return succeeded;
+    }
+
+    private MailboxACL manageMailboxACL(MailboxACL.MailboxACLEntryKey mailboxACLEntryKey, MailboxACL.EditMode editMode, MailboxACL.MailboxACLRights mailboxAclRights, MailboxACL acl) throws UnsupportedRightException {
+        switch (editMode) {
+            case ADD:
+                return acl.union(mailboxACLEntryKey, mailboxAclRights);
+            case REMOVE:
+                return acl.except(mailboxACLEntryKey, mailboxAclRights);
+            case REPLACE:
+                return acl.replace(mailboxACLEntryKey, mailboxAclRights);
+            default:
+                throw new IllegalStateException("Unexpected " + MailboxACL.EditMode.class.getName() + "." + editMode);
+        }
+    }
 }
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraSession.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraSession.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraSession.java	2014-12-17 16:04:47.600086583 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraSession.java	2014-12-17 17:14:11.803600045 +0100
@@ -31,7 +31,7 @@
 
 /**
  * A Cassandra session with the default keyspace
- * 
+ *
  */
 public class CassandraSession implements Session {
     private final static String DEFAULT_CLUSTER_IP = "localhost";
@@ -52,13 +52,17 @@
     private void initDatabase(Cluster cluster, String keyspace, int replicationFactor) {
         session = cluster.connect();
         session.execute("CREATE KEYSPACE IF NOT EXISTS " + keyspace + " WITH replication " + "= {'class':'SimpleStrategy', 'replication_factor':" + replicationFactor + "};");
-        session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + ".mailbox (" + "id uuid PRIMARY KEY," + "name text, namespace text," + "uidvalidity bigint," + "user text," + "path text" + ");");
+        session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + ".mailbox (" + "id uuid PRIMARY KEY," + "name text, namespace text," + "uidvalidity bigint," + "user text," + "path text," + "acl text," + "acl_version bigint," + ");");
         session.execute("CREATE INDEX IF NOT EXISTS ON " + keyspace + ".mailbox(path);");
         session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + ".messageCounter (" + "mailboxId UUID PRIMARY KEY," + "nextUid bigint," + ");");
         session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + ".mailboxCounters (" + "mailboxId UUID PRIMARY KEY," + "count counter," + "unseen counter," + "nextModSeq counter" + ");");
         session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + ".message (" + "mailboxId UUID," + "uid bigint," + "internalDate timestamp," + "bodyStartOctet int," + "content blob," + "modSeq bigint," + "mediaType text," + "subType text," + "fullContentOctets int," + "bodyOctets int,"
                 + "textualLineCount bigint," + "bodyContent blob," + "headerContent blob," + "flagAnswered boolean," + "flagDeleted boolean," + "flagDraft boolean," + "flagRecent boolean," + "flagSeen boolean," + "flagFlagged boolean," + "flagUser boolean," + "PRIMARY KEY (mailboxId, uid)" + ");");
         session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + ".subscription (" + "user text," + "mailbox text," + "PRIMARY KEY (mailbox, user)" + ");");
+        session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + ".quota (" + "user text PRIMARY KEY," + "size_quota counter," + "count_quota counter" + ");");
+        session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + ".quota_max (" + "user text PRIMARY KEY," + "size_quota_max bigint," + "count_quota_max bigint" + ");");
+        session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + ".default_max_quota_table (" + "id int PRIMARY KEY," + "default_max_size_quota bigint," + "default_max_count_quota bigint" + ");");
+        session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + ".group_membership ("+"user text,"+"group text,"+"PRIMARY KEY (user, group)"+");");
         session.close();
     }
 
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java	2014-12-17 16:04:47.600086583 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java	2014-12-17 17:14:11.800266711 +0100
@@ -22,7 +22,6 @@
 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.select;
-
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.FIELDS;
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.ID;
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.NAME;
@@ -31,16 +30,18 @@
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.TABLE_NAME;
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.UIDVALIDITY;
 import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.USER;
+import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.ACL;
+import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.ACL_VERSION;
 
 import java.util.List;
 import java.util.UUID;
 
+import org.apache.james.mailbox.cassandra.mail.model.CassandraMailbox;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.store.mail.MailboxMapper;
 import org.apache.james.mailbox.store.mail.model.Mailbox;
-import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
 
 import com.datastax.driver.core.ResultSet;
 import com.datastax.driver.core.Row;
@@ -49,6 +50,8 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableList.Builder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Data access management for mailbox.
@@ -76,8 +79,8 @@
         }
     }
 
-    private SimpleMailbox<UUID> mailbox(Row row) {
-        SimpleMailbox<UUID> mailbox = new SimpleMailbox<UUID>(new MailboxPath(row.getString(NAMESPACE), row.getString(USER), row.getString(NAME)), row.getLong(UIDVALIDITY));
+    private CassandraMailbox<UUID> mailbox(Row row) {
+        CassandraMailbox<UUID> mailbox = new CassandraMailbox<UUID>(new MailboxPath(row.getString(NAMESPACE), row.getString(USER), row.getString(NAME)), row.getLong(UIDVALIDITY), session);
         mailbox.setMailboxId(row.getUUID(ID));
         return mailbox;
     }
@@ -97,16 +100,16 @@
 
     @Override
     public void save(Mailbox<UUID> mailbox) throws MailboxException {
-        Preconditions.checkArgument(mailbox instanceof SimpleMailbox<?>);
-        SimpleMailbox<UUID> simpleMailbox = (SimpleMailbox<UUID>) mailbox;
-        if (simpleMailbox.getMailboxId() == null) {
-            simpleMailbox.setMailboxId(UUID.randomUUID());
+        Preconditions.checkArgument(mailbox instanceof CassandraMailbox);
+        CassandraMailbox<UUID> cassandraMailbox = (CassandraMailbox<UUID>) mailbox;
+        if (cassandraMailbox.getMailboxId() == null) {
+            cassandraMailbox.setMailboxId(UUID.randomUUID());
         }
-        upsertMailbox(simpleMailbox);
+        upsertMailbox(cassandraMailbox);
     }
 
-    private void upsertMailbox(SimpleMailbox<UUID> mailbox) {
-        session.execute(insertInto(TABLE_NAME).value(ID, mailbox.getMailboxId()).value(NAME, mailbox.getName()).value(NAMESPACE, mailbox.getNamespace()).value(UIDVALIDITY, mailbox.getUidValidity()).value(USER, mailbox.getUser()).value(PATH, path(mailbox).toString()));
+    private void upsertMailbox(CassandraMailbox mailbox) {
+        session.execute(insertInto(TABLE_NAME).value(ID, mailbox.getMailboxId()).value(NAME, mailbox.getName()).value(NAMESPACE, mailbox.getNamespace()).value(UIDVALIDITY, mailbox.getUidValidity()).value(USER, mailbox.getUser()).value(PATH, path(mailbox).toString()).value(ACL, "{}").value(ACL_VERSION, 0));
     }
 
     private MailboxPath path(Mailbox<?> mailbox) {
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/model/CassandraMailbox.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/model/CassandraMailbox.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/model/CassandraMailbox.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/model/CassandraMailbox.java	2014-12-17 17:14:11.800266711 +0100
@@ -0,0 +1,179 @@
+/****************************************************************
+ * 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.mailbox.cassandra.mail.model;
+
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.Session;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import org.apache.james.mailbox.cassandra.table.CassandraMailboxTable;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.SimpleMailboxACL;
+import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.update;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.set;
+
+
+/**
+ * Mailbox implementation for Cassandra. It overrides SimpleMailbox class, adding ACL support
+ * ( stored in Cassandra ) and expose specific methods to allow check-and-set ACL management
+ * in  CassandraMessageManager
+ */
+public class CassandraMailbox<Id> extends SimpleMailbox<Id> {
+
+    private Session session;
+
+    private static final Logger LOG = LoggerFactory.getLogger(CassandraMailbox.class);
+
+    public CassandraMailbox(MailboxPath path, long uidValidity, Session session) {
+        super(path, uidValidity);
+        this.session = session;
+    }
+
+    @Override
+    public MailboxACL getACL() {
+        // Get the ACL string from Cassandra
+        ResultSet resultSet = session.execute(
+                select(CassandraMailboxTable.ACL)
+                        .from(CassandraMailboxTable.TABLE_NAME)
+                        .where(
+                                eq(CassandraMailboxTable.ID, getMailboxId())
+                        )
+        );
+        if(resultSet.isExhausted()) {
+            // No mailbox. Should not happen : return null
+            return null;
+        }
+        String aclJson = resultSet.one().getString(CassandraMailboxTable.ACL);
+        return convertIntoMailboxACL(aclJson);
+    }
+
+    private MailboxACL convertIntoMailboxACL(String aclJson) {
+        MailboxACL result = SimpleMailboxACL.EMPTY;
+        try {
+            result = SimpleMailboxACLJsonConverter.toACL(aclJson);
+        } catch (JsonParseException parseException) {
+            LOG.error(aclJson + " provided as ACL is malformed for mailbox " + this.getMailboxId());
+        } catch ( JsonMappingException mappingException) {
+            LOG.error(aclJson + " provided as ACL does not correspond to an ACL for mailbox " + this.getMailboxId());
+        } catch( IOException ioException) {
+            LOG.error("IOException while parsing JSON for mailbox " + this.getMailboxId());
+        }
+        return result;
+    }
+
+    public class ACLWithVersion {
+        public long version;
+        public MailboxACL acl;
+    }
+
+    /**
+     * Get the ACL and the version number.
+     *
+     * @return The ACL of this mailbox with its version number
+     */
+    public ACLWithVersion getACLWithVersion() {
+        ACLWithVersion result = new ACLWithVersion();
+        ResultSet resultSet = session.execute(
+                select(CassandraMailboxTable.FIELDS)
+                        .from(CassandraMailboxTable.TABLE_NAME)
+                        .where(
+                                eq(CassandraMailboxTable.ID, getMailboxId())
+                        )
+        );
+        if(resultSet.isExhausted()) {
+            result.version = 0;
+            result.acl = SimpleMailboxACL.EMPTY;
+            return result;
+        }
+        Row row = resultSet.one();
+        String aclJson = row.getString(CassandraMailboxTable.ACL);
+        result.version = row.getLong(CassandraMailboxTable.ACL_VERSION);
+        result.acl = convertIntoMailboxACL(aclJson);
+        return result;
+    }
+
+    /**
+     * Not concurrency safe AT ALL ! Do not use !
+     * @param acl The mailbox ACL to set
+     */
+    @Override
+    public void setACL(MailboxACL acl) {
+        String jsonACL;
+        try {
+            jsonACL = SimpleMailboxACLJsonConverter.toJson(acl);
+        } catch(JsonProcessingException processingException) {
+            LOG.error("Can not set acl for mailbox " + this.getMailboxId());
+            return;
+        }
+        session.execute(
+                update(CassandraMailboxTable.TABLE_NAME)
+                        .with(
+                                set(CassandraMailboxTable.ACL, jsonACL)
+                        )
+                        .where(eq(CassandraMailboxTable.ID, getMailboxId()))
+        );
+    }
+
+    /**
+     * Set ACL implementation for Cassandra using test and set CQL instruction
+     *
+     * @param acl Mailbox ACLs to set
+     * @return True if it succeeded, False if the version of the ACL is not the one specified in ACL version
+     */
+    public boolean setACLWithVersion(MailboxACL acl, long version ) {
+        long newVersionNumber = version + 1;
+        String jsonACL;
+        try {
+            jsonACL = SimpleMailboxACLJsonConverter.toJson(acl);
+        } catch(JsonProcessingException processingException) {
+            LOG.error("Can not set acl for mailbox " + this.getMailboxId());
+            return true;
+        }
+        ResultSet resultSet = session.execute(
+                update(CassandraMailboxTable.TABLE_NAME)
+                        .with(
+                                set(CassandraMailboxTable.ACL, jsonACL)
+                        )
+                        .and(
+                                set(CassandraMailboxTable.ACL_VERSION, newVersionNumber)
+                        )
+                        .where(
+                                eq(CassandraMailboxTable.ID, getMailboxId())
+                        )
+                        .onlyIf(
+                                eq(CassandraMailboxTable.ACL_VERSION, version)
+                        )
+
+        );
+        return resultSet.one().getBool("[applied]");
+    }
+
+}
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/model/SimpleMailboxACLJsonConverter.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/model/SimpleMailboxACLJsonConverter.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/model/SimpleMailboxACLJsonConverter.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/model/SimpleMailboxACLJsonConverter.java	2014-12-17 17:14:11.800266711 +0100
@@ -0,0 +1,98 @@
+/****************************************************************
+ * 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.mailbox.cassandra.mail.model;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.apache.james.mailbox.exception.UnsupportedRightException;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.apache.james.mailbox.model.SimpleMailboxACL;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Convert the ACL in Json and convert Json back to ACL
+ */
+public class SimpleMailboxACLJsonConverter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SimpleMailboxACLJsonConverter.class);
+
+    /**
+     * Convert an ACL to JSON in order to store it in Cassandra
+     *
+     * @param acl ACL you want to Jsonify
+     * @return A Json representing your ACL
+     */
+    public static String toJson(MailboxACL acl) throws JsonProcessingException {
+        Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> entries = acl.getEntries();
+        Set<Map.Entry<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights>> set = entries.entrySet();
+        Map<String,Integer> convertedEntries = new HashMap<String, Integer>();
+        for(Map.Entry<MailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> entry : set) {
+            SimpleMailboxACL.Rfc4314Rights rights;
+            try{
+                rights = (SimpleMailboxACL.Rfc4314Rights) entry.getValue();
+            } catch(ClassCastException classCastException) {
+                LOG.warn("Cast Exception : you need to provide a Rfc4314Rights object when instantiating ACLs");
+                break;
+            }
+            convertedEntries.put(entry.getKey().serialize(), rights.getValue());
+        }
+        ObjectMapper mapper = new ObjectMapper();
+        return mapper.writeValueAsString(convertedEntries);
+    }
+
+    /**
+     * Get back your ACL from a JSON string
+     *
+     * A malformed Json is equivalent to an empty ACL
+     *
+     * @param jsonACLString Json string representing your ACL
+     * @return The ACL represented by your Json
+     */
+    public static MailboxACL toACL(String jsonACLString) throws JsonParseException, JsonMappingException, IOException {
+        ObjectMapper mapper = new ObjectMapper();
+        Map<String,Integer> convertedEntries = mapper.readValue(jsonACLString,
+                new TypeReference<Map<String, Integer>>() { } );
+        Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> entries = new HashMap<MailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights>();
+        Set<Map.Entry<String, Integer>> convertedEntrySet = convertedEntries.entrySet();
+        for(Map.Entry<String, Integer> entry : convertedEntrySet) {
+            SimpleMailboxACL.Rfc4314Rights rights;
+            try {
+                rights = new SimpleMailboxACL.Rfc4314Rights(entry.getValue());
+            } catch(UnsupportedRightException rightException) {
+                LOG.warn("Integer provided as right is out of range, causing an unsupported right exception");
+                break;
+            }
+            MailboxACL.MailboxACLEntryKey key = new SimpleMailboxACL.SimpleMailboxACLEntryKey(entry.getKey());
+            entries.put(key, rights);
+        }
+        return new SimpleMailboxACL(entries);
+    }
+
+}
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraFixedQuotaManager.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraFixedQuotaManager.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraFixedQuotaManager.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraFixedQuotaManager.java	2014-12-17 17:09:55.653588965 +0100
@@ -0,0 +1,96 @@
+/****************************************************************
+ * 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.mailbox.cassandra.quota;
+
+import com.datastax.driver.core.Session;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.store.StoreMailboxManager;
+
+/**
+ * Allow you to create a FixedQuotaManager where all users have the same limit.
+ */
+public class CassandraFixedQuotaManager extends CassandraListeningQuotaManager {
+
+
+    public CassandraFixedQuotaManager(StoreMailboxManager<?> manager, Session session) throws MailboxException {
+        super(manager, session);
+    }
+
+    /**
+     * Return the maximum storage which is allowed for the given {@link org.apache.james.mailbox.MailboxSession} (in fact the user which the session is bound to)
+     *
+     * The returned valued must be in <strong>bytes</strong>
+     *
+     * @param session
+     * @return maxBytes
+     * @throws MailboxException
+     */
+    protected long getMaxStorage(MailboxSession session) throws MailboxException {
+        return quotaStorage.getDefaultMaxStorage();
+    }
+
+
+    /**
+     * Return the maximum message count which is allowed for the given {@link org.apache.james.mailbox.MailboxSession} (in fact the user which the session is bound to)
+     *
+     * @param session
+     * @return maximum of allowed message count
+     * @throws MailboxException
+     */
+    protected long getMaxMessage(MailboxSession session) throws MailboxException {
+        return quotaStorage.getDefaultMaxMessageCount();
+    }
+
+    /**
+     * Proxy method allowing you to set the maximum storage quota for a given user
+     *
+     * @param user This user
+     * @param maxStorageQuota The new storage quota ( in bytes ) for this user
+     */
+    public void setUserMaxStorage(String user, long maxStorageQuota) {
+
+    }
+
+    /**
+     * Proxy method allowing you to set the maximum message count allowed for this user
+     * @param user This user
+     * @param maxMessageCount The new message count allowed for this user.
+     */
+    public void setUserMaxMessage(String user, long maxMessageCount) {
+
+    }
+
+    /**
+     *  Proxy method allowing you to set the default maximum storage in bytes.
+     * @param defaultMaxStorage new default maximum storage
+     */
+    public void setDefaultMaxStorage(long defaultMaxStorage) {
+        quotaStorage.setDefaultMaxStorage(defaultMaxStorage);
+    }
+
+    /**
+     *  Proxy method allowing you to set the default maximum message count allowed
+     * @param defaultMaxMessageCount new default message count
+     */
+    public void setDefaultMaxMessage(long defaultMaxMessageCount) {
+        quotaStorage.setDefaultMaxMessageCount(defaultMaxMessageCount);
+    }
+
+}
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraListeningQuotaManager.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraListeningQuotaManager.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraListeningQuotaManager.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraListeningQuotaManager.java	2014-12-17 17:09:55.653588965 +0100
@@ -0,0 +1,232 @@
+/****************************************************************
+ * 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.mailbox.cassandra.quota;
+
+import com.datastax.driver.core.Session;
+import org.apache.james.mailbox.MailboxListener;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.QuotaManager;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.model.Quota;
+import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
+import org.apache.james.mailbox.store.StoreMailboxManager;
+import org.apache.james.mailbox.store.mail.MessageMapper;
+import org.apache.james.mailbox.store.mail.model.Mailbox;
+import org.apache.james.mailbox.store.mail.model.Message;
+import org.apache.james.mailbox.store.quota.QuotaImpl;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * {@link QuotaManager} which will keep track of quota by listing for {@link org.apache.james.mailbox.MailboxListener.Event}'s.
+ *
+ * The whole quota is kept in Cassandra after it was lazy-fetched on the first access
+ *  *
+ */
+public abstract class CassandraListeningQuotaManager implements QuotaManager, MailboxListener {
+    private MailboxSessionMapperFactory factory;
+    private boolean calculateWhenUnlimited = false;
+    protected CassandraQuotaStorage quotaStorage;
+
+    public CassandraListeningQuotaManager(StoreMailboxManager<?> manager, Session session) throws MailboxException {
+        this.factory = manager.getMapperFactory();
+        manager.addGlobalListener(this, null);
+        this.quotaStorage = new CassandraQuotaStorage(session);
+    }
+
+    protected MailboxSessionMapperFactory<?> getFactory() {
+        return factory;
+    }
+
+    /**
+     * Allow you to tune default behaviour when facing unlimited quota
+     *
+     * @param calculateWhenUnlimited If true, quota are re - calculated when unlimited
+     */
+    public void setCalculateUsedWhenUnlimited(boolean calculateWhenUnlimited) {
+        this.calculateWhenUnlimited  = calculateWhenUnlimited;
+    }
+
+    /**
+     * Calculate the current message count for the user owning this MailboxSession
+     *
+     * This method is slow ( linear in the number of mailboxes ). It is only called once for each user maximum.
+     *
+     * @param session MailboxSession of the user
+     * @return The number of messages of all mailboxes belonging to this user.
+     * @throws MailboxException
+     */
+    private long constructMessageCount(MailboxSession session) throws MailboxException {
+        long mc = 0;
+        List<Mailbox> mailboxes = factory.getMailboxMapper(session).findMailboxWithPathLike(new MailboxPath(session.getPersonalSpace(), session.getUser().getUserName(), "%"));
+        for (int i = 0; i < mailboxes.size(); i++) {
+            mc += factory.getMessageMapper(session).countMessagesInMailbox(mailboxes.get(i));
+        }
+        return mc;
+    }
+
+    /**
+     * Calculate the current size of all the mailboxes of the user ( in bytes ).
+     *
+     * This method is slow ( linear in the number of mailboxes and in messages contained in these mailboxes). It is only called once for each user maximum.
+     *
+     *
+     * @param session
+     * @return
+     * @throws MailboxException
+     */
+    private long calculateMailboxesSize(MailboxSession session) throws MailboxException {
+        MessageMapper mapper = factory.getMessageMapper(session);
+        long mSizes = 0;
+        List<Mailbox> mailboxes = factory.getMailboxMapper(session).findMailboxWithPathLike(new MailboxPath(session.getPersonalSpace(), session.getUser().getUserName(), "%"));
+        for (int i = 0; i < mailboxes.size(); i++) {
+            Iterator<Message> messages = mapper.findInMailbox(mailboxes.get(i), MessageRange.all(), MessageMapper.FetchType.Metadata, -1);
+
+            while(messages.hasNext()) {
+                mSizes +=  messages.next().getFullContentOctets();
+            }
+        }
+        return mSizes;
+    }
+
+    /**
+     * Return the message quota for the user owning this MailboxSession
+     *
+     * @param session MailboxSession of this user
+     * @return Quota for message count for this user
+     * @throws MailboxException
+     */
+    @Override
+    public Quota getMessageQuota(MailboxSession session) throws MailboxException {
+        long max = getMaxMessage(session);
+        if (max != Quota.UNLIMITED || calculateWhenUnlimited) {
+
+            String id = session.getUser().getUserName();
+            AtomicLong count = quotaStorage.getCount(id);
+            if (count == null) {
+                long messageCount = constructMessageCount(session);
+                count = new AtomicLong(messageCount);
+                long mailboxesSize = calculateMailboxesSize(session);
+                quotaStorage.setUserQuotas(session.getUser().getUserName(), messageCount, mailboxesSize);
+            }
+            return QuotaImpl.quota(max, count.get());
+        } else {
+            return QuotaImpl.unlimited();
+        }
+    }
+
+    /**
+     * Return the storage quota for the user owning this MailboxSession
+     *
+     * @param session This mailbox session
+     * @return The storage quota for the user user owning this mailboxSession
+     * @throws MailboxException
+     */
+    @Override
+    public Quota getStorageQuota(MailboxSession session) throws MailboxException {
+        long max = getMaxStorage(session);
+        if (max != Quota.UNLIMITED || calculateWhenUnlimited) {
+            MessageMapper mapper = factory.getMessageMapper(session);
+            String id = session.getUser().getUserName();
+            AtomicLong size = quotaStorage.getSize(id);
+
+            if (size == null) {
+                long messageCount = constructMessageCount(session);
+                long mailboxesSize = calculateMailboxesSize(session);
+                size = new AtomicLong(mailboxesSize);
+                quotaStorage.setUserQuotas(session.getUser().getUserName(), messageCount, mailboxesSize);
+            }
+            return QuotaImpl.quota(max, size.get());
+        } else {
+            return QuotaImpl.unlimited();
+        }
+    }
+
+    /**
+     * Return the maximum storage which is allowed for the given {@link MailboxSession} (in fact the user which the session is bound to)
+     *
+     * The returned valued must be in <strong>bytes</strong>
+     *
+     * @param session
+     * @return maxBytes
+     * @throws MailboxException
+     */
+    protected abstract long getMaxStorage(MailboxSession session) throws MailboxException;
+
+
+    /**
+     * Return the maximum message count which is allowed for the given {@link MailboxSession} (in fact the user which the session is bound to)
+     *
+     * @param session
+     * @return maximum of allowed message count
+     * @throws MailboxException
+     */
+    protected abstract long getMaxMessage(MailboxSession session) throws MailboxException;
+
+
+    @Override
+    public void event(MailboxListener.Event event) {
+        String id = event.getSession().getUser().getUserName();
+        if (event instanceof MailboxListener.Added) {
+            MailboxListener.Added added = (MailboxListener.Added) event;
+
+            long s = 0;
+            long c = 0;
+            Iterator<Long> uids = added.getUids().iterator();;
+            while(uids.hasNext()) {
+                long uid = uids.next();
+                s += added.getMetaData(uid).getSize();
+                c++;
+            }
+
+            quotaStorage.addCount(id, c);
+            quotaStorage.addCount(id, s);
+        } else if (event instanceof MailboxListener.Expunged) {
+            MailboxListener.Expunged expunged = (MailboxListener.Expunged) event;
+            long s = 0;
+            long c = 0;
+            Iterator<Long> uids = expunged.getUids().iterator();
+            while(uids.hasNext()) {
+                long uid = uids.next();
+                s += expunged.getMetaData(uid).getSize();
+                c++;
+            }
+
+            quotaStorage.addCount(id, -c);
+            quotaStorage.addCount(id, -s);
+        } else if (event instanceof MailboxAdded) {
+            // Trick : creates the row initialized with zero values
+            quotaStorage.addCount(id, 0);
+        }
+    }
+
+    /**
+     * Get never closed
+     *
+     * @return false
+     */
+    public boolean isClosed() {
+        return false;
+    }
+
+}
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserQuotaManager.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserQuotaManager.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserQuotaManager.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraPerUserQuotaManager.java	2014-12-17 17:09:55.653588965 +0100
@@ -0,0 +1,95 @@
+/****************************************************************
+ * 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.mailbox.cassandra.quota;
+
+import com.datastax.driver.core.Session;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.store.StoreMailboxManager;
+
+/**
+ * Allow you to set a per user quota stored in Cassandra
+ */
+public class CassandraPerUserQuotaManager extends CassandraListeningQuotaManager {
+
+    public CassandraPerUserQuotaManager(StoreMailboxManager<?> manager, Session session) throws MailboxException {
+        super(manager, session);
+    }
+
+    /**
+     * Return the maximum storage which is allowed for the given {@link MailboxSession} (in fact the user which the session is bound to)
+     *
+     * The returned valued must be in <strong>bytes</strong>
+     *
+     * @param session
+     * @return maxBytes
+     * @throws MailboxException
+     */
+    protected long getMaxStorage(MailboxSession session) throws MailboxException {
+        return quotaStorage.getMaxMailboxSize(session.getUser().getUserName());
+    }
+
+
+    /**
+     * Return the maximum message count which is allowed for the given {@link MailboxSession} (in fact the user which the session is bound to)
+     *
+     * @param session
+     * @return maximum of allowed message count
+     * @throws MailboxException
+     */
+    protected long getMaxMessage(MailboxSession session) throws MailboxException {
+        return quotaStorage.getMaxMessageCont(session.getUser().getUserName());
+    }
+
+    /**
+     * Proxy method allowing you to set the maximum storage quota for a given user
+     *
+     * @param user This user
+     * @param maxStorageQuota The new storage quota ( in bytes ) for this user
+     */
+    public void setUserMaxStorage(String user, long maxStorageQuota) {
+        quotaStorage.setMaxMailboxSize(user, maxStorageQuota);
+    }
+
+    /**
+     * Proxy method allowing you to set the maximum message count allowed for this user
+     * @param user This user
+     * @param maxMessageCount The new message count allowed for this user.
+     */
+    public void setUserMaxMessage(String user, long maxMessageCount) {
+        quotaStorage.setMaxMessageCount(user, maxMessageCount);
+    }
+
+    /**
+     *  Proxy method allowing you to set the default maximum storage in bytes.
+     * @param defaultMaxStorage new default maximum storage
+     */
+    public void setDefaultMaxStorage(long defaultMaxStorage) {
+        quotaStorage.setDefaultMaxStorage(defaultMaxStorage);
+    }
+
+    /**
+     *  Proxy method allowing you to set the default maximum message count allowed
+     * @param defaultMaxMessageCount new default message count
+     */
+    public void setDefaultMaxMessage(long defaultMaxMessageCount) {
+        quotaStorage.setDefaultMaxMessageCount(defaultMaxMessageCount);
+    }
+
+}
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraQuotaStorage.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraQuotaStorage.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraQuotaStorage.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/quota/CassandraQuotaStorage.java	2014-12-17 17:09:55.653588965 +0100
@@ -0,0 +1,264 @@
+/****************************************************************
+ * 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.mailbox.cassandra.quota;
+
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Session;
+import org.apache.james.mailbox.cassandra.table.CassandraDefaultMaxQuotaTable;
+import org.apache.james.mailbox.cassandra.table.CassandraMaxQuotaTable;
+import org.apache.james.mailbox.model.Quota;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.*;
+import static org.apache.james.mailbox.cassandra.table.CassandraQuotaTable.COUNT_QUOTA;
+import static org.apache.james.mailbox.cassandra.table.CassandraQuotaTable.SIZE_QUOTA;
+import static org.apache.james.mailbox.cassandra.table.CassandraQuotaTable.TABLE_NAME;
+import static org.apache.james.mailbox.cassandra.table.CassandraQuotaTable.USER;
+
+/**
+ * This class is responsible for managing quota storage into Cassandra
+ */
+public class CassandraQuotaStorage {
+
+    private Session session;
+
+    CassandraQuotaStorage(Session session) {
+        this.session = session;
+    }
+
+    AtomicLong getCount(String user) {
+        ResultSet resultSet = session.execute(
+                select(COUNT_QUOTA)
+                        .from(TABLE_NAME)
+                        .where(
+                                eq(USER, user)
+                        )
+        );
+        if(resultSet.isExhausted() ) {
+            return null;
+        }
+        return new AtomicLong( resultSet.one().getLong(COUNT_QUOTA) );
+    }
+
+    AtomicLong getSize(String user) {
+        ResultSet resultSet = session.execute(
+                select(SIZE_QUOTA)
+                        .from(TABLE_NAME)
+                        .where(
+                                eq(USER, user)
+                        )
+        );
+        if(resultSet.isExhausted() ) {
+            return null;
+        }
+        return new AtomicLong( resultSet.one().getLong(SIZE_QUOTA) );
+    }
+
+    AtomicLong setUserQuotas(String user, long messageCount, long mailboxesSize) {
+        String query = "UPDATE "+TABLE_NAME
+                +" SET "+COUNT_QUOTA+"="+COUNT_QUOTA+"+"+messageCount+","
+                +SIZE_QUOTA+"="+SIZE_QUOTA+"+"+mailboxesSize
+                +" WHERE "+USER+"='"+user+"';";
+        session.execute(query);
+        return new AtomicLong( messageCount );
+    }
+
+    void addCount(String user, long addedCount) {
+        String query = "UPDATE " + TABLE_NAME
+                 + " SET "+COUNT_QUOTA + "="+ COUNT_QUOTA +"+"+addedCount
+                 + " WHERE " + USER +"='"+user+"'";
+        session.execute(query);
+    }
+
+    void addSize(String user, long addedSize) {
+        String query = "UPDATE " + TABLE_NAME
+                + " SET "+SIZE_QUOTA +"="+SIZE_QUOTA+"+"+addedSize
+                + " WHERE " + USER +"='"+user+"'";
+        session.execute(query);
+    }
+
+    long getMaxMailboxSize(String user) {
+        ResultSet resultSet = session.execute(
+                select(CassandraMaxQuotaTable.SIZE_QUOTA_MAX)
+                        .from(CassandraMaxQuotaTable.TABLE_NAME)
+                        .where(eq(CassandraMaxQuotaTable.USER,user))
+        );
+        if(resultSet.isExhausted()) {
+            // No specified max value for this user. Return max value instead.
+            return getDefaultMaxStorage();
+        }
+        long quota_value = resultSet.one().getLong(CassandraMaxQuotaTable.SIZE_QUOTA_MAX);
+        if( quota_value == Quota.UNKNOWN) {
+            return getDefaultMaxStorage();
+        }
+        return quota_value;
+    }
+
+    long getMaxMessageCont(String user) {
+        ResultSet resultSet = session.execute(
+                select(CassandraMaxQuotaTable.COUNT_QUOTA_MAX)
+                        .from(CassandraMaxQuotaTable.TABLE_NAME)
+                        .where(eq(CassandraMaxQuotaTable.USER,user))
+        );
+        if(resultSet.isExhausted()) {
+            // No specified max value for this user. Return max value instead.
+            return getDefaultMaxMessageCount();
+        }
+        long quota_value = resultSet.one().getLong(CassandraMaxQuotaTable.COUNT_QUOTA_MAX);
+        if( quota_value == Quota.UNKNOWN) {
+            return getDefaultMaxMessageCount();
+        }
+        return quota_value;
+    }
+
+    void setMaxMailboxSize(String user, long maxMailboxSize) {
+        createFieldsForUser(user);
+        session.execute(
+                update(CassandraMaxQuotaTable.TABLE_NAME)
+                        .with(
+                                set(CassandraMaxQuotaTable.SIZE_QUOTA_MAX, maxMailboxSize)
+                        )
+                        .where(
+                                eq(CassandraMaxQuotaTable.USER, user)
+                        )
+        );
+    }
+
+    void setMaxMessageCount(String user, long maxMessageCount) {
+        createFieldsForUser(user);
+        session.execute(
+                update(CassandraMaxQuotaTable.TABLE_NAME)
+                        .with(
+                                set(CassandraMaxQuotaTable.COUNT_QUOTA_MAX, maxMessageCount)
+                        )
+                        .where(
+                                eq(CassandraMaxQuotaTable.USER, user)
+                        )
+        );
+    }
+
+    long getDefaultMaxStorage() {
+        ResultSet resultSet = session.execute(
+                select(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_SIZE_QUOTA)
+                        .from(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_QUOTA_TABLE)
+                        .where(
+                                eq(CassandraDefaultMaxQuotaTable.ID, 1)
+                        )
+        );
+        if(resultSet.isExhausted()) {
+            // No value specified. Set default max quotas to Quota.unlimited
+            session.execute(
+                    insertInto(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_QUOTA_TABLE)
+                            .value(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_SIZE_QUOTA, Quota.UNLIMITED)
+                            .value(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_COUNT_QUOTA, Quota.UNLIMITED)
+                            .value(CassandraDefaultMaxQuotaTable.ID, 1)
+            );
+            return Quota.UNLIMITED;
+        }
+        return resultSet.one().getLong(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_SIZE_QUOTA);
+
+    }
+
+    long getDefaultMaxMessageCount() {
+        ResultSet resultSet = session.execute(
+                select(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_COUNT_QUOTA)
+                        .from(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_QUOTA_TABLE)
+                        .where(
+                                eq(CassandraDefaultMaxQuotaTable.ID, 1)
+                        )
+        );
+        if(resultSet.isExhausted()) {
+            // No value specified. Set default max quotas to Quota.unlimited
+            session.execute(
+                    insertInto(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_QUOTA_TABLE)
+                            .value(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_SIZE_QUOTA, Quota.UNLIMITED)
+                            .value(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_COUNT_QUOTA, Quota.UNLIMITED)
+                            .value(CassandraDefaultMaxQuotaTable.ID, 1)
+            );
+            return Quota.UNLIMITED;
+        }
+        return resultSet.one().getLong(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_COUNT_QUOTA);
+    }
+
+    void setDefaultMaxMessageCount(long defaultMaxMessageCount) {
+        if(defaultRowExist()) {
+            session.execute(
+                    update(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_QUOTA_TABLE)
+                            .with(
+                                    set(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_COUNT_QUOTA, defaultMaxMessageCount)
+                            )
+                            .where(
+                                eq(CassandraDefaultMaxQuotaTable.ID,1)
+                        )
+            );
+        } else {
+            //We need to insert the configuration row. Set Quota.UNLIMITED as storage max default value
+            session.execute(
+                    insertInto(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_QUOTA_TABLE)
+                            .value(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_SIZE_QUOTA, Quota.UNLIMITED)
+                            .value(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_COUNT_QUOTA, defaultMaxMessageCount)
+                            .value(CassandraDefaultMaxQuotaTable.ID, 1)
+            );
+        }
+    }
+
+    void setDefaultMaxStorage(long defaultMaxStorage) {
+        if(defaultRowExist()) {
+            session.execute(
+                    update(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_QUOTA_TABLE)
+                            .with(
+                                    set(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_SIZE_QUOTA, defaultMaxStorage)
+                            )
+                            .where(
+                                    eq(CassandraDefaultMaxQuotaTable.ID,1)
+                            )
+            );
+        } else {
+            //We need to insert the configuration row. Set Quota.UNLIMITED as storage max default value
+            session.execute(
+                    insertInto(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_QUOTA_TABLE)
+                            .value(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_SIZE_QUOTA, defaultMaxStorage)
+                            .value(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_COUNT_QUOTA, Quota.UNLIMITED)
+                            .value(CassandraDefaultMaxQuotaTable.ID, 1)
+            );
+        }
+    }
+
+    private boolean defaultRowExist() {
+        // Check if ID 1 exists
+        ResultSet resultSet = session.execute(
+                select(CassandraDefaultMaxQuotaTable.ID)
+                        .from(CassandraDefaultMaxQuotaTable.DEFAULT_MAX_QUOTA_TABLE)
+                        .where(
+                                eq(CassandraDefaultMaxQuotaTable.ID,1)
+                        )
+        );
+        return !resultSet.isExhausted();
+    }
+
+    private void createFieldsForUser(String user) {
+        session.execute(insertInto(CassandraMaxQuotaTable.TABLE_NAME)
+                        .value(CassandraMaxQuotaTable.USER, user)
+                        .value(CassandraMaxQuotaTable.SIZE_QUOTA_MAX, Quota.UNKNOWN )
+                        .value(CassandraMaxQuotaTable.COUNT_QUOTA_MAX, Quota.UNKNOWN )
+                        .ifNotExists()
+        );
+    }
+}
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraDefaultMaxQuotaTable.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraDefaultMaxQuotaTable.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraDefaultMaxQuotaTable.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraDefaultMaxQuotaTable.java	2014-12-17 17:09:55.653588965 +0100
@@ -0,0 +1,26 @@
+/****************************************************************
+ * 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.mailbox.cassandra.table;
+
+public interface CassandraDefaultMaxQuotaTable {
+    String DEFAULT_MAX_QUOTA_TABLE = "default_max_quota_table";
+    String ID = "id";
+    String DEFAULT_MAX_SIZE_QUOTA = "default_max_size_quota";
+    String DEFAULT_MAX_COUNT_QUOTA = "default_max_count_quota";
+}
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraGroupMembershipTable.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraGroupMembershipTable.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraGroupMembershipTable.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraGroupMembershipTable.java	2014-12-17 17:09:55.653588965 +0100
@@ -0,0 +1,26 @@
+/****************************************************************
+ * 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.mailbox.cassandra.table;
+
+public interface CassandraGroupMembershipTable {
+    String TABLE = "group_membership";
+    String GROUP = "group";
+    String USER = "user";
+}
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMailboxTable.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMailboxTable.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMailboxTable.java	2014-12-17 16:04:47.600086583 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMailboxTable.java	2014-12-17 17:14:11.800266711 +0100
@@ -27,5 +27,7 @@
     String NAMESPACE = "namespace";
     String UIDVALIDITY = "uidvalidity";
     String NAME = "name";
-    String[] FIELDS = { ID, USER, NAMESPACE, UIDVALIDITY, NAME, PATH };
+    String ACL = "acl";
+    String ACL_VERSION = "acl_version";
+    String[] FIELDS = { ID, USER, NAMESPACE, UIDVALIDITY, NAME, PATH, ACL, ACL_VERSION };
 }
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMaxQuotaTable.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMaxQuotaTable.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMaxQuotaTable.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMaxQuotaTable.java	2014-12-17 17:09:55.653588965 +0100
@@ -0,0 +1,26 @@
+/****************************************************************
+ * 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.mailbox.cassandra.table;
+
+public interface CassandraMaxQuotaTable {
+    String TABLE_NAME = "quota_max";
+    String USER = "user";
+    String SIZE_QUOTA_MAX = "size_quota_max";
+    String COUNT_QUOTA_MAX = "count_quota_max";
+}
diff -uNr james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraQuotaTable.java james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraQuotaTable.java
--- james-mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraQuotaTable.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraQuotaTable.java	2014-12-17 17:09:55.653588965 +0100
@@ -0,0 +1,26 @@
+/****************************************************************
+ * 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.mailbox.cassandra.table;
+
+public interface CassandraQuotaTable {
+    String TABLE_NAME = "quota";
+    String USER = "user";
+    String SIZE_QUOTA = "size_quota";
+    String COUNT_QUOTA = "count_quota";
+}
diff -uNr james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraClusterSingleton.java james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraClusterSingleton.java
--- james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraClusterSingleton.java	2014-12-17 16:04:47.600086583 +0100
+++ james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraClusterSingleton.java	2014-12-17 17:16:16.773605450 +0100
@@ -40,7 +40,7 @@
 
     /**
      * Builds a MiniCluster instance.
-     * 
+     *
      * @return the {@link CassandraClusterSingleton} instance
      * @throws RuntimeException
      */
@@ -57,16 +57,17 @@
             EmbeddedCassandraServerHelper.startEmbeddedCassandra();
             // Let Cassandra initialization before creating
             // the session. Solve very fast computer tests run.
-            Thread.sleep(2000);
+            Thread.sleep(4000);
             this.session = new CassandraSession(CLUSTER_IP, CLUSTER_PORT_TEST, KEYSPACE_NAME, DEFAULT_REPLICATION_FACTOR);
         } catch (Exception e) {
+            e.printStackTrace();
             throw new RuntimeException(e);
         }
     }
 
     /**
      * Return a configuration for the runnning MiniCluster.
-     * 
+     *
      * @return
      */
     public Session getConf() {
@@ -75,13 +76,13 @@
 
     /**
      * Create a specific table.
-     * 
+     *
      * @param tableName
      *            the table name
      */
     public void ensureTable(String tableName) {
         if (tableName.equals("mailbox")) {
-            session.execute("CREATE TABLE IF NOT EXISTS " + session.getLoggedKeyspace() + ".mailbox (" + "id uuid PRIMARY KEY," + "name text, namespace text," + "uidvalidity bigint," + "user text," + "path text" + ");");
+            session.execute("CREATE TABLE IF NOT EXISTS " + session.getLoggedKeyspace() + ".mailbox (" + "id uuid PRIMARY KEY," + "name text, namespace text," + "uidvalidity bigint," + "user text," + "path text," + "acl text," + "acl_version bigint" + ");");
 
             session.execute("CREATE INDEX IF NOT EXISTS ON " + session.getLoggedKeyspace() + ".mailbox(path);");
         } else if (tableName.equals("messageCounter")) {
@@ -94,6 +95,30 @@
                     + "PRIMARY KEY (mailboxId, uid)" + ");");
         } else if (tableName.equals("subscription")) {
             session.execute("CREATE TABLE IF NOT EXISTS " + session.getLoggedKeyspace() + ".subscription (" + "user text," + "mailbox text," + "PRIMARY KEY (mailbox, user)" + ");");
+        } else if (tableName.equals("quota")) {
+            session.execute("CREATE TABLE IF NOT EXISTS " + session.getLoggedKeyspace() + ".quota ("
+                    + "user text PRIMARY KEY,"
+                    + "size_quota counter,"
+                    + "count_quota counter"
+                    + ");");
+        } else if (tableName.equals("quota_max")) {
+            session.execute("CREATE TABLE IF NOT EXISTS " + session.getLoggedKeyspace() + ".quota_max ("
+                    + "user text PRIMARY KEY,"
+                    + "size_quota_max bigint,"
+                    + "count_quota_max bigint"
+                    + ");");
+        } else if(tableName.equals("default_max_quota_table")) {
+            session.execute("CREATE TABLE IF NOT EXISTS " + session.getLoggedKeyspace() + ".default_max_quota_table ("
+                    + "id int PRIMARY KEY,"
+                    + "default_max_size_quota bigint,"
+                    + "default_max_count_quota bigint"
+                    + ");");
+        } else if(tableName.equals("group_membership")) {
+            session.execute("CREATE TABLE IF NOT EXISTS " + session.getLoggedKeyspace() + ".group_membership("
+                    + "user text,"
+                    + "group text,"
+                    + "PRIMARY KEY (user,group)"
+                    + ");");
         } else {
             throw new NotImplementedException("We don't support the class " + tableName);
         }
@@ -107,11 +132,15 @@
         ensureTable("mailboxCounters");
         ensureTable("message");
         ensureTable("subscription");
+        ensureTable("quota");
+        ensureTable("quota_max");
+        ensureTable("default_max_quota_table");
+        ensureTable("group_membership");
     }
 
     /**
      * Delete all rows from specified table.
-     * 
+     *
      * @param tableName
      */
     public void clearTable(String tableName) {
@@ -126,6 +155,11 @@
         clearTable("mailboxCounters");
         clearTable("message");
         clearTable("subscription");
+        clearTable("quota");
+        clearTable("quota_max");
+        clearTable("default_max_quota_table");
+        clearTable("group_membership");
+
     }
 
 }
diff -uNr james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraGroupMembershipTest.java james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraGroupMembershipTest.java
--- james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraGroupMembershipTest.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraGroupMembershipTest.java	2014-12-17 17:09:55.653588965 +0100
@@ -0,0 +1,44 @@
+/****************************************************************
+ * 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.mailbox.cassandra;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+/**
+ * Tests the CassandraGroupMembershipResolver class.
+ */
+public class CassandraGroupMembershipTest {
+    @Test
+    public void testGroupMembership() {
+        CassandraClusterSingleton CLUSTER = CassandraClusterSingleton.build();
+        CLUSTER.ensureAllTables();
+        CassandraGroupMembershipResolver groupMembershipResolver = new CassandraGroupMembershipResolver(CLUSTER.getConf());
+        assertFalse(groupMembershipResolver.isMember("benwa", "Linagora"));
+        groupMembershipResolver.addMembership("Linagora", "benwa");
+        assertFalse(groupMembershipResolver.isMember("benwa", "Renault"));
+        assertTrue(groupMembershipResolver.isMember("benwa", "Linagora"));
+        groupMembershipResolver.removeMembership("Linagora","benwa");
+        assertFalse(groupMembershipResolver.isMember("benwa","Linagora"));
+        CLUSTER.clearAllTables();
+    }
+}
diff -uNr james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
--- james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java	2014-12-16 17:49:32.163262333 +0100
+++ james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java	2014-12-17 17:14:11.800266711 +0100
@@ -28,9 +28,11 @@
 import java.util.UUID;
 
 import org.apache.james.mailbox.cassandra.CassandraClusterSingleton;
+import org.apache.james.mailbox.cassandra.mail.model.CassandraMailbox;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.SimpleMailboxACL;
 import org.apache.james.mailbox.store.mail.model.Mailbox;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
 import org.junit.Before;
@@ -82,6 +84,9 @@
         testSave();
         testDelete();
         testHasChildren();
+        testAclInitialisation();
+        testSetACLMethod();
+        testSetAclWithVersion();
         // testDeleteAllMemberships(); // Ignore this test
     }
 
@@ -119,7 +124,7 @@
             if (i % 2 == 0) {
                 newPath.setUser(null);
             }
-            addMailbox(new SimpleMailbox<UUID>(newPath, 1234));
+            addMailbox(new CassandraMailbox<UUID>(newPath, 1234, CLUSTER.getConf()));
         }
         result = mapper.findMailboxWithPathLike(path);
         assertEquals(end - start + 1, result.size());
@@ -209,6 +214,38 @@
         }
     }
 
+    private void testAclInitialisation() {
+        CassandraMailbox<UUID> mailbox = (CassandraMailbox<UUID>) mailboxList.get(0);
+        assertEquals(SimpleMailboxACL.EMPTY, mailbox.getACL());
+        CassandraMailbox.ACLWithVersion aclWithVersion = mailbox.getACLWithVersion();
+        assertEquals(SimpleMailboxACL.EMPTY, aclWithVersion.acl);
+        assertEquals(aclWithVersion.version, 0);
+    }
+
+    private void testSetAclWithVersion() {
+        CassandraMailbox<UUID> mailbox = (CassandraMailbox<UUID>) mailboxList.get(0);
+        mailbox.setACL(SimpleMailboxACL.EMPTY);
+        assertEquals(SimpleMailboxACL.EMPTY, mailbox.getACL());
+        mailbox.setACLWithVersion(SimpleMailboxACL.OWNER_FULL_ACL, 0);
+        CassandraMailbox.ACLWithVersion aclWithVersion = mailbox.getACLWithVersion();
+        assertEquals(SimpleMailboxACL.OWNER_FULL_ACL, aclWithVersion.acl);
+        assertEquals(1, aclWithVersion.version);
+    }
+
+    /**
+     * Test if a mailbox can store and retrieve its ACLs
+     */
+    private void testSetACLMethod() {
+        // Find a mailbox
+        CassandraMailbox<UUID> mailbox = (CassandraMailbox<UUID>) mailboxList.get(0);
+        // Test a setACL
+        mailbox.setACL(SimpleMailboxACL.OWNER_FULL_ACL);
+        assertEquals(SimpleMailboxACL.OWNER_FULL_ACL, mailbox.getACL());
+        CassandraMailbox.ACLWithVersion aclWithVersion = mailbox.getACLWithVersion();
+        assertEquals(SimpleMailboxACL.OWNER_FULL_ACL, aclWithVersion.acl);
+        assertEquals(0, aclWithVersion.version);
+    }
+
     private static void fillMailboxList() {
         mailboxList = new ArrayList<SimpleMailbox<UUID>>();
         pathsList = new ArrayList<MailboxPath>();
@@ -224,14 +261,14 @@
                     }
                     path = new MailboxPath("namespace" + i, "user" + j, name);
                     pathsList.add(path);
-                    mailboxList.add(new SimpleMailbox<UUID>(path, 13));
+                    mailboxList.add(new CassandraMailbox<UUID>(path, 13, CLUSTER.getConf()));
                 }
             }
         }
         LOG.info("Created test case with {} mailboxes and {} paths", mailboxList.size(), pathsList.size());
     }
 
-    private void addMailbox(SimpleMailbox<UUID> mailbox) throws MailboxException {
+    private void addMailbox(CassandraMailbox<UUID> mailbox) throws MailboxException {
         mailboxList.add(mailbox);
         pathsList.add(new MailboxPath(mailbox.getNamespace(), mailbox.getUser(), mailbox.getName()));
         mapper.save(mailbox);
diff -uNr james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidAndModSeqProviderTest.java james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidAndModSeqProviderTest.java
--- james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidAndModSeqProviderTest.java	2014-12-16 17:49:32.159929000 +0100
+++ james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidAndModSeqProviderTest.java	2014-12-17 17:14:11.800266711 +0100
@@ -25,6 +25,7 @@
 import java.util.UUID;
 
 import org.apache.james.mailbox.cassandra.CassandraClusterSingleton;
+import org.apache.james.mailbox.cassandra.mail.model.CassandraMailbox;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
 import org.junit.Before;
@@ -82,7 +83,7 @@
                     }
                     path = new MailboxPath("namespace" + i, "user" + j, name);
                     pathsList.add(path);
-                    mailboxList.add(new SimpleMailbox<UUID>(path, 13));
+                    mailboxList.add(new CassandraMailbox<UUID>(path, 13, CLUSTER.getConf()));
                 }
             }
         }
@@ -97,7 +98,7 @@
     public void testLastUid() throws Exception {
         LOG.info("lastUid");
         final MailboxPath path = new MailboxPath("gsoc", "ieugen", "Trash");
-        final SimpleMailbox<UUID> newBox = new SimpleMailbox<UUID>(path, 1234);
+        final SimpleMailbox<UUID> newBox = new CassandraMailbox<UUID>(path, 1234, CLUSTER.getConf());
         mapper.save(newBox);
         mailboxList.add(newBox);
         pathsList.add(path);
@@ -133,7 +134,7 @@
         LOG.info("highestModSeq");
         LOG.info("lastUid");
         MailboxPath path = new MailboxPath("gsoc", "ieugen", "Trash");
-        SimpleMailbox<UUID> newBox = new SimpleMailbox<UUID>(path, 1234);
+        SimpleMailbox<UUID> newBox = new CassandraMailbox<UUID>(path, 1234, CLUSTER.getConf());
         mapper.save(newBox);
         mailboxList.add(newBox);
         pathsList.add(path);
diff -uNr james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/SimpleMailboxACLJsonConverterTest.java james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/SimpleMailboxACLJsonConverterTest.java
--- james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/SimpleMailboxACLJsonConverterTest.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/SimpleMailboxACLJsonConverterTest.java	2014-12-17 17:14:11.800266711 +0100
@@ -0,0 +1,127 @@
+/****************************************************************
+ * 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.mailbox.cassandra.mail;
+
+import org.apache.james.mailbox.cassandra.mail.model.SimpleMailboxACLJsonConverter;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.apache.james.mailbox.model.SimpleMailboxACL;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test the converter of a simple ACL into Json
+ */
+public class SimpleMailboxACLJsonConverterTest {
+
+    @Test
+    public void testEmptyACLToJson() throws Exception {
+        MailboxACL emptyACL = SimpleMailboxACL.EMPTY;
+        assertEquals("{}", SimpleMailboxACLJsonConverter.toJson(emptyACL));
+    }
+
+    @Test
+    public void testSingleUserEntryToJson() throws Exception {
+        Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map = new HashMap<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights>();
+        addSingleUserEntryToMap(map);
+        MailboxACL acl = new SimpleMailboxACL(map);
+        assertEquals("{\"-user\":2040}", SimpleMailboxACLJsonConverter.toJson(acl));
+    }
+
+    private void addSingleUserEntryToMap(Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map) {
+        SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(false, true, true, true, false, true, false, true, true, true, true);
+        SimpleMailboxACL.MailboxACLEntryKey key = new SimpleMailboxACL.SimpleMailboxACLEntryKey("user", MailboxACL.NameType.user, true);
+        map.put(key, rights);
+    }
+
+    @Test
+    public void testSingleGroupEntryToJson() throws Exception {
+        Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map = new HashMap<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights>();
+        addSingleGroupEntryToMap(map);
+        MailboxACL acl = new SimpleMailboxACL(map);
+        assertEquals("{\"-$group\":2032}", SimpleMailboxACLJsonConverter.toJson(acl));
+    }
+
+    private void addSingleGroupEntryToMap(Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map) {
+        SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(false, false, true, true, false, true, false, true, true, true, true);
+        SimpleMailboxACL.MailboxACLEntryKey key = new SimpleMailboxACL.SimpleMailboxACLEntryKey("group", MailboxACL.NameType.group, true);
+        map.put(key, rights);
+    }
+
+    @Test
+    public void testSingleEntryToJson() throws Exception {
+        Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map = new HashMap<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights>();
+        addSingleSpecialEntryToMap(map);
+        MailboxACL acl = new SimpleMailboxACL(map);
+        assertEquals("{\"-special\":1968}", SimpleMailboxACLJsonConverter.toJson(acl));
+    }
+
+    private void addSingleSpecialEntryToMap(Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map) {
+        SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(false, false, true, true, false, true, false, true, false, true, true);
+        SimpleMailboxACL.MailboxACLEntryKey key = new SimpleMailboxACL.SimpleMailboxACLEntryKey("special", MailboxACL.NameType.special, true);
+        map.put(key, rights);
+    }
+
+    @Test
+    public void testMultipleEntriesToJson() throws Exception {
+        Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map = new HashMap<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights>();
+        addSingleUserEntryToMap(map);
+        addSingleGroupEntryToMap(map);
+        MailboxACL acl = new SimpleMailboxACL(map);
+        assertEquals("{\"-user\":2040,\"-$group\":2032}", SimpleMailboxACLJsonConverter.toJson(acl));
+    }
+
+    @Test
+    public void testEmptyACLFromJson() throws Exception {
+        String aclString = "{}";
+        assertEquals(SimpleMailboxACL.EMPTY, SimpleMailboxACLJsonConverter.toACL(aclString));
+    }
+
+    @Test
+    public void testSingleUserEntryFromJson() throws Exception {
+        String aclString = "{\"-user\":2040}";
+        Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map = new HashMap<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights>();
+        addSingleUserEntryToMap(map);
+        MailboxACL acl = new SimpleMailboxACL(map);
+        assertEquals(acl, SimpleMailboxACLJsonConverter.toACL(aclString));
+    }
+
+    @Test
+    public void testSingleGroupEntryFromJson() throws Exception {
+        String aclString = "{\"-$group\":2032}";
+        Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map = new HashMap<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights>();
+        addSingleGroupEntryToMap(map);
+        MailboxACL acl = new SimpleMailboxACL(map);
+        assertEquals(acl, SimpleMailboxACLJsonConverter.toACL(aclString));
+    }
+
+    @Test
+    public void testMultipleEntriesFromJson() throws Exception {
+        String aclString = "{\"-$group\":2032,\"-user\":2040}";
+        Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map = new HashMap<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights>();
+        addSingleUserEntryToMap(map);
+        addSingleGroupEntryToMap(map);
+        MailboxACL acl = new SimpleMailboxACL(map);
+        assertEquals(acl, SimpleMailboxACLJsonConverter.toACL(aclString));
+    }
+}
diff -uNr james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/CassandraQuotaStorageTest.java james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/CassandraQuotaStorageTest.java
--- james-mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/CassandraQuotaStorageTest.java	1970-01-01 01:00:00.000000000 +0100
+++ james-mailbox-new/cassandra/src/test/java/org/apache/james/mailbox/cassandra/quota/CassandraQuotaStorageTest.java	2014-12-17 17:09:55.653588965 +0100
@@ -0,0 +1,163 @@
+/****************************************************************
+ * 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.mailbox.cassandra.quota;
+
+import org.apache.james.mailbox.cassandra.CassandraClusterSingleton;
+import org.apache.james.mailbox.model.Quota;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Run tests for CassandraQuotaStorage.
+ */
+public class CassandraQuotaStorageTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CassandraQuotaStorageTest.class);
+    public static final CassandraClusterSingleton CLUSTER = CassandraClusterSingleton.build();
+    private static CassandraQuotaStorage quotaStorage = new CassandraQuotaStorage(CLUSTER.getConf());
+
+    @Before
+    public void setUp() throws Exception {
+        LOG.info("Set up for tests for Quotas over Cassandra");
+        CLUSTER.ensureAllTables();
+        CLUSTER.clearAllTables();
+    }
+
+    @After
+    public void cleanUp() {
+        CLUSTER.clearAllTables();
+    }
+
+    @Test
+    public void testSetUserQuota() {
+        quotaStorage.setUserQuotas("benwa", 42, 524);
+        quotaStorage.setUserQuotas("toto", 24, 444);
+        quotaStorage.setUserQuotas("tata", 56, 965);
+
+        assertEquals(42, quotaStorage.getCount("benwa").get() );
+        assertEquals(24, quotaStorage.getCount("toto").get() );
+        assertEquals(56, quotaStorage.getCount("tata").get() );
+
+        assertEquals(524, quotaStorage.getSize("benwa").get() );
+        assertEquals(444, quotaStorage.getSize("toto").get() );
+        assertEquals(965, quotaStorage.getSize("tata").get() );
+    }
+
+    @Test
+    public void testAddCountQuotaStorage() {
+        quotaStorage.addCount("toubib",0);
+        assertEquals(0, quotaStorage.getCount("toubib").get() );
+
+        quotaStorage.setUserQuotas("benwa", 42, 524);
+        quotaStorage.setUserQuotas("toto", 24, 444);
+        quotaStorage.setUserQuotas("tata", 56, 965);
+
+        quotaStorage.addCount("benwa", 36);
+        quotaStorage.addCount("toto", -12);
+        quotaStorage.addCount("tata", 0);
+
+        assertEquals(78, quotaStorage.getCount("benwa").get() );
+        assertEquals(12, quotaStorage.getCount("toto").get() );
+        assertEquals(56, quotaStorage.getCount("tata").get() );
+    }
+
+    @Test
+    public void testAddSizeQuotaStorage() {
+        quotaStorage.addCount("toubib",0);
+        assertEquals(0, quotaStorage.getCount("toubib").get() );
+
+        quotaStorage.setUserQuotas("benwa", 42, 524);
+        quotaStorage.setUserQuotas("toto", 24, 444);
+        quotaStorage.setUserQuotas("tata", 56, 965);
+
+        quotaStorage.addSize("benwa", 102);
+        quotaStorage.addSize("toto", -56);
+        quotaStorage.addSize("tata", 0);
+
+        assertEquals(626, quotaStorage.getSize("benwa").get() );
+        assertEquals(388, quotaStorage.getSize("toto").get() );
+        assertEquals(965, quotaStorage.getSize("tata").get() );
+    }
+
+    @Test
+    public void testGetDefaultMaxMessageCount() {
+        assertEquals(Quota.UNLIMITED, quotaStorage.getDefaultMaxMessageCount() );
+    }
+
+    @Test
+    public void testGetDefaultMaxStorage() {
+        assertEquals(Quota.UNLIMITED, quotaStorage.getDefaultMaxStorage() );
+    }
+
+    @Test
+    public void testSetDefaultMaxMessageCount() {
+        quotaStorage.setDefaultMaxMessageCount(42);
+        assertEquals(42, quotaStorage.getDefaultMaxMessageCount());
+    }
+
+    @Test
+    public void testSetDefaultMaxStorage() {
+        quotaStorage.setDefaultMaxStorage(421);
+        assertEquals(421, quotaStorage.getDefaultMaxStorage());
+    }
+
+    @Test
+    public void testGetMaxMessageCont() {
+        quotaStorage.setDefaultMaxMessageCount(42);
+        assertEquals(42,quotaStorage.getMaxMessageCont("benwa"));
+    }
+
+    @Test
+    public void testSetMaxMessageCont() {
+        quotaStorage.setMaxMessageCount("benwa",84);
+        assertEquals(84, quotaStorage.getMaxMessageCont("benwa"));
+    }
+
+    @Test
+    public void testGetMaxMailboxSize() {
+        quotaStorage.setMaxMailboxSize("benwa", 421);
+        assertEquals(421, quotaStorage.getMaxMailboxSize("benwa"));
+    }
+
+    @Test
+    public void testSetMaxMailboxSize() {
+        quotaStorage.setMaxMailboxSize("benwa", 842);
+        assertEquals(842,quotaStorage.getMaxMailboxSize("benwa"));
+    }
+
+    @Test
+    public void testSetMailboxSizeInteractionOnGetMailboxSizeDefaultBehavior() {
+        quotaStorage.setMaxMailboxSize("benwa", 1024);
+        quotaStorage.setDefaultMaxMessageCount(102);
+        assertEquals(102, quotaStorage.getMaxMessageCont("benwa"));
+    }
+
+    @Test
+    public void testSetMessageCountInteractionOnGetMailboxSizeDefaultBehavior() {
+        quotaStorage.setMaxMessageCount("benwa", 102);
+        quotaStorage.setDefaultMaxStorage(2048);
+        assertEquals(2048, quotaStorage.getMaxMailboxSize("benwa"));
+    }
+}

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to