You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by er...@apache.org on 2015/05/08 17:02:21 UTC
svn commit: r1678368 - in /james/mailbox/trunk:
api/src/main/java/org/apache/james/mailbox/exception/ cassandra/
cassandra/src/main/java/org/apache/james/mailbox/cassandra/
cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/
cassandra/src/...
Author: eric
Date: Fri May 8 15:02:21 2015
New Revision: 1678368
URL: http://svn.apache.org/r1678368
Log:
Add ACL persitance for Cassandra Mailbox, patch contributed by Tellier Benoit (MAILBOX-224)
Added:
james/mailbox/trunk/api/src/main/java/org/apache/james/mailbox/exception/MalformedSoredACLException.java
james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/
james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/FunctionRunnerWithRetry.java
james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/SimpleMailboxACLJsonConverter.java
james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraACLTable.java
james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java
james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/
james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/FunctionRunnerWithRetryTest.java
james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/SimpleMailboxACLJsonConverterTest.java
Modified:
james/mailbox/trunk/api/src/main/java/org/apache/james/mailbox/exception/UnsupportedRightException.java
james/mailbox/trunk/cassandra/pom.xml
james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraSession.java
james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraClusterSingleton.java
james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidAndModSeqProviderTest.java
Added: james/mailbox/trunk/api/src/main/java/org/apache/james/mailbox/exception/MalformedSoredACLException.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/api/src/main/java/org/apache/james/mailbox/exception/MalformedSoredACLException.java?rev=1678368&view=auto
==============================================================================
--- james/mailbox/trunk/api/src/main/java/org/apache/james/mailbox/exception/MalformedSoredACLException.java (added)
+++ james/mailbox/trunk/api/src/main/java/org/apache/james/mailbox/exception/MalformedSoredACLException.java Fri May 8 15:02:21 2015
@@ -0,0 +1,38 @@
+/*
+ * 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.exception;
+
+public class MalformedSoredACLException extends MailboxException {
+
+ public MalformedSoredACLException() {
+
+ }
+
+ public MalformedSoredACLException(String message) {
+ super(message);
+ }
+
+ public MalformedSoredACLException(String msg, Exception cause) {
+ super(msg, cause);
+ }
+
+
+}
Modified: james/mailbox/trunk/api/src/main/java/org/apache/james/mailbox/exception/UnsupportedRightException.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/api/src/main/java/org/apache/james/mailbox/exception/UnsupportedRightException.java?rev=1678368&r1=1678367&r2=1678368&view=diff
==============================================================================
--- james/mailbox/trunk/api/src/main/java/org/apache/james/mailbox/exception/UnsupportedRightException.java (original)
+++ james/mailbox/trunk/api/src/main/java/org/apache/james/mailbox/exception/UnsupportedRightException.java Fri May 8 15:02:21 2015
@@ -44,7 +44,11 @@ public class UnsupportedRightException e
public UnsupportedRightException(MailboxACLRight unsupportedRight) {
this(unsupportedRight.getValue());
}
-
+
+ public UnsupportedRightException(String msg, Exception cause) {
+ super(msg, cause);
+ }
+
public char getUnsupportedRight() {
return unsupportedRight;
}
Modified: james/mailbox/trunk/cassandra/pom.xml
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/pom.xml?rev=1678368&r1=1678367&r2=1678368&view=diff
==============================================================================
--- james/mailbox/trunk/cassandra/pom.xml (original)
+++ james/mailbox/trunk/cassandra/pom.xml Fri May 8 15:02:21 2015
@@ -31,11 +31,6 @@
<description>Apache James Mailbox implementation over Cassandra</description>
<name>Apache James :: Mailbox :: Cassandra</name>
- <properties>
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
- </properties>
-
<dependencies>
<dependency>
<groupId>${javax.mail.groupId}</groupId>
@@ -75,11 +70,20 @@
<version>${cassandra-driver-core.version}</version>
</dependency>
<dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit</artifactId>
<version>${cassandra-unit.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<profiles>
@@ -211,6 +215,14 @@
</descriptorRefs>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
</plugins>
</build>
</profile>
Modified: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java?rev=1678368&r1=1678367&r2=1678368&view=diff
==============================================================================
--- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java (original)
+++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java Fri May 8 15:02:21 2015
@@ -27,6 +27,7 @@ import org.apache.james.mailbox.acl.Simp
import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.SimpleMailboxACL;
import org.apache.james.mailbox.store.Authenticator;
import org.apache.james.mailbox.store.StoreMailboxManager;
import org.apache.james.mailbox.store.StoreMessageManager;
@@ -46,7 +47,9 @@ public class CassandraMailboxManager ext
@Override
protected Mailbox<UUID> doCreateMailbox(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
- return new SimpleMailbox<UUID>(mailboxPath, randomUidValidity());
+ SimpleMailbox<UUID> cassandraMailbox = new SimpleMailbox<>(mailboxPath, randomUidValidity());
+ cassandraMailbox.setACL(SimpleMailboxACL.EMPTY);
+ return cassandraMailbox;
}
@Override
Modified: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java?rev=1678368&r1=1678367&r2=1678368&view=diff
==============================================================================
--- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java (original)
+++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java Fri May 8 15:02:21 2015
@@ -39,14 +39,22 @@ import com.datastax.driver.core.Session;
*
*/
public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFactory<UUID> {
+ private static final int DEFAULT_MAX_RETRY = 1000;
+
private Session session;
private CassandraUidProvider uidProvider;
private ModSeqProvider<UUID> modSeqProvider;
+ private int maxRetry;
public CassandraMailboxSessionMapperFactory(CassandraUidProvider uidProvider, ModSeqProvider<UUID> modSeqProvider, CassandraSession session) {
this.uidProvider = uidProvider;
this.modSeqProvider = modSeqProvider;
this.session = session;
+ this.maxRetry = DEFAULT_MAX_RETRY;
+ }
+
+ public void setMaxRetry(int maxRetry) {
+ this.maxRetry = maxRetry;
}
@Override
@@ -56,7 +64,7 @@ public class CassandraMailboxSessionMapp
@Override
public MailboxMapper<UUID> createMailboxMapper(MailboxSession mailboxSession) {
- return new CassandraMailboxMapper(session);
+ return new CassandraMailboxMapper(session, maxRetry);
}
@Override
@@ -71,4 +79,8 @@ public class CassandraMailboxSessionMapp
public UidProvider<UUID> getUidProvider() {
return uidProvider;
}
+
+ Session getSession() {
+ return session;
+ }
}
Modified: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraSession.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraSession.java?rev=1678368&r1=1678367&r2=1678368&view=diff
==============================================================================
--- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraSession.java (original)
+++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraSession.java Fri May 8 15:02:21 2015
@@ -31,13 +31,15 @@ import com.google.common.util.concurrent
/**
* A Cassandra session with the default keyspace
- *
+ *
*/
public class CassandraSession implements Session {
private final static String DEFAULT_CLUSTER_IP = "localhost";
private final static int DEFAULT_CLUSTER_PORT = 9042;
private final static String DEFAULT_KEYSPACE_NAME = "apache_james";
private final static int DEFAULT_REPLICATION_FACTOR = 1;
+
+ public static final int LIGHTWEIGHT_TRANSACTION_APPLIED = 0;
private Session session;
@@ -59,6 +61,7 @@ public class CassandraSession implements
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," + "flagVersion bigint," + "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 + ".acl (id uuid PRIMARY KEY, acl text, version bigint);");
session.close();
}
Added: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java?rev=1678368&view=auto
==============================================================================
--- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java (added)
+++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java Fri May 8 15:02:21 2015
@@ -0,0 +1,182 @@
+/****************************************************************
+ * 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 com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.Session;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import org.apache.james.mailbox.cassandra.CassandraSession;
+import org.apache.james.mailbox.cassandra.mail.utils.SimpleMailboxACLJsonConverter;
+import org.apache.james.mailbox.cassandra.mail.utils.FunctionRunnerWithRetry;
+import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
+import org.apache.james.mailbox.cassandra.table.CassandraMailboxTable;
+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.mail.model.Mailbox;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Optional;
+import java.util.UUID;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.update;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.set;
+
+public class CassandraACLMapper {
+
+ @FunctionalInterface
+ public interface CodeInjector {
+ void inject();
+ }
+
+ private final Mailbox<UUID> mailbox;
+ private final Session session;
+ private final int maxRetry;
+ private final CodeInjector codeInjector;
+
+ private static final Logger LOG = LoggerFactory.getLogger(CassandraACLMapper.class);
+
+ public CassandraACLMapper(Mailbox<UUID> mailbox, Session session, int maxRetry) {
+ this(mailbox, session, maxRetry, () -> {});
+ }
+
+ public CassandraACLMapper(Mailbox<UUID> mailbox, Session session, int maxRetry, CodeInjector codeInjector) {
+ Preconditions.checkArgument(maxRetry > 0);
+ Preconditions.checkArgument(mailbox.getMailboxId() != null);
+ this.mailbox = mailbox;
+ this.session = session;
+ this.maxRetry = maxRetry;
+ this.codeInjector = codeInjector;
+ }
+
+ public MailboxACL getACL() {
+ ResultSet resultSet = getStoredACLRow();
+ if (resultSet.isExhausted()) {
+ return SimpleMailboxACL.EMPTY;
+ }
+ String serializedACL = resultSet.one().getString(CassandraACLTable.ACL);
+ return deserializeACL(serializedACL);
+ }
+
+ public void updateACL(final MailboxACL.MailboxACLCommand command) throws MailboxException {
+ new FunctionRunnerWithRetry(maxRetry).execute(
+ () -> {
+ codeInjector.inject();
+ ResultSet resultSet = getAclWithVersion()
+ .map((x) -> x.apply(command))
+ .map(this::updateStoredACL)
+ .orElseGet(() -> insertACL(applyCommandOnEmptyACL(command)));
+ return resultSet.one().getBool(CassandraSession.LIGHTWEIGHT_TRANSACTION_APPLIED);
+ }
+ );
+ }
+
+ private MailboxACL applyCommandOnEmptyACL(MailboxACL.MailboxACLCommand command) {
+ try {
+ return SimpleMailboxACL.EMPTY.apply(command);
+ } catch (UnsupportedRightException exception) {
+ throw Throwables.propagate(exception);
+ }
+ }
+
+ private ResultSet getStoredACLRow() {
+ return session.execute(
+ select(CassandraACLTable.ACL, CassandraACLTable.VERSION)
+ .from(CassandraACLTable.TABLE_NAME)
+ .where(eq(CassandraMailboxTable.ID, mailbox.getMailboxId()))
+ );
+ }
+
+ private ResultSet updateStoredACL(ACLWithVersion aclWithVersion) {
+ try {
+ return session.execute(
+ update(CassandraACLTable.TABLE_NAME)
+ .with(set(CassandraACLTable.ACL, SimpleMailboxACLJsonConverter.toJson(aclWithVersion.mailboxACL)))
+ .and(set(CassandraACLTable.VERSION, aclWithVersion.version + 1))
+ .where(eq(CassandraACLTable.ID, mailbox.getMailboxId()))
+ .onlyIf(eq(CassandraACLTable.VERSION, aclWithVersion.version))
+ );
+ } catch (JsonProcessingException exception) {
+ throw Throwables.propagate(exception);
+ }
+ }
+
+ private ResultSet insertACL(MailboxACL acl) {
+ try {
+ return session.execute(
+ insertInto(CassandraACLTable.TABLE_NAME)
+ .value(CassandraACLTable.ID, mailbox.getMailboxId())
+ .value(CassandraACLTable.ACL, SimpleMailboxACLJsonConverter.toJson(acl))
+ .value(CassandraACLTable.VERSION, 0)
+ .ifNotExists()
+ );
+ } catch (JsonProcessingException exception) {
+ throw Throwables.propagate(exception);
+ }
+ }
+
+ private Optional<ACLWithVersion> getAclWithVersion() {
+ ResultSet resultSet = getStoredACLRow();
+ if (resultSet.isExhausted()) {
+ return Optional.empty();
+ }
+ Row row = resultSet.one();
+ return Optional.of(new ACLWithVersion(row.getLong(CassandraACLTable.VERSION), deserializeACL(row.getString(CassandraACLTable.ACL))));
+ }
+
+ private MailboxACL deserializeACL(String serializedACL) {
+ try {
+ return SimpleMailboxACLJsonConverter.toACL(serializedACL);
+ } catch(IOException exception) {
+ LOG.error("Unable to read stored ACL. " +
+ "We will use empty ACL instead." +
+ "Mailbox is {}:{}:{} ." +
+ "ACL is {}", mailbox.getNamespace(), mailbox.getUser(), mailbox.getName(), serializedACL, exception);
+ return SimpleMailboxACL.EMPTY;
+ }
+ }
+
+ private class ACLWithVersion {
+ private final long version;
+ private final MailboxACL mailboxACL;
+
+ public ACLWithVersion(long version, MailboxACL mailboxACL) {
+ this.version = version;
+ this.mailboxACL = mailboxACL;
+ }
+
+ public ACLWithVersion apply(MailboxACL.MailboxACLCommand command) {
+ try {
+ return new ACLWithVersion(version, mailboxACL.apply(command));
+ } catch(UnsupportedRightException exception) {
+ throw Throwables.propagate(exception);
+ }
+ }
+ }
+}
Modified: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java?rev=1678368&r1=1678367&r2=1678368&view=diff
==============================================================================
--- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java (original)
+++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java Fri May 8 15:02:21 2015
@@ -19,37 +19,27 @@
package org.apache.james.mailbox.cassandra.mail;
-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;
-import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.NAMESPACE;
-import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.PATH;
-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 com.datastax.driver.core.querybuilder.QueryBuilder.*;
+import static org.apache.james.mailbox.cassandra.table.CassandraMailboxTable.*;
import java.util.List;
import java.util.UUID;
+import com.google.common.base.Preconditions;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.MailboxNotFoundException;
import org.apache.james.mailbox.model.MailboxACL;
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;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.querybuilder.QueryBuilder;
-import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
+import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
/**
* Data access management for mailbox.
@@ -57,9 +47,11 @@ import com.google.common.collect.Immutab
public class CassandraMailboxMapper implements MailboxMapper<UUID> {
private Session session;
+ private int maxRetry;
- public CassandraMailboxMapper(Session session) {
+ public CassandraMailboxMapper(Session session, int maxRetry) {
this.session = session;
+ this.maxRetry = maxRetry;
}
@Override
@@ -68,7 +60,7 @@ public class CassandraMailboxMapper impl
}
@Override
- public Mailbox<UUID> findMailboxByPath(MailboxPath path) throws MailboxException, MailboxNotFoundException {
+ public Mailbox<UUID> findMailboxByPath(MailboxPath path) throws MailboxException {
ResultSet resultSet = session.execute(select(FIELDS).from(TABLE_NAME).where(eq(PATH, path.toString())));
if (resultSet.isExhausted()) {
throw new MailboxNotFoundException(path);
@@ -80,6 +72,7 @@ public class CassandraMailboxMapper impl
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));
mailbox.setMailboxId(row.getUUID(ID));
+ mailbox.setACL(new CassandraACLMapper(mailbox, session, maxRetry).getACL());
return mailbox;
}
@@ -98,16 +91,24 @@ public class CassandraMailboxMapper impl
@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 SimpleMailbox);
+ SimpleMailbox<UUID> cassandraMailbox = (SimpleMailbox<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(SimpleMailbox<UUID> mailbox) throws MailboxException {
+ 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 MailboxPath path(Mailbox<?> mailbox) {
@@ -147,6 +148,7 @@ public class CassandraMailboxMapper impl
@Override
public void updateACL(Mailbox<UUID> mailbox, MailboxACL.MailboxACLCommand mailboxACLCommand) throws MailboxException {
- mailbox.setACL(mailbox.getACL().apply(mailboxACLCommand));
+ new CassandraACLMapper(mailbox, session, maxRetry).updateACL(mailboxACLCommand);
}
+
}
Added: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/FunctionRunnerWithRetry.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/FunctionRunnerWithRetry.java?rev=1678368&view=auto
==============================================================================
--- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/FunctionRunnerWithRetry.java (added)
+++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/FunctionRunnerWithRetry.java Fri May 8 15:02:21 2015
@@ -0,0 +1,45 @@
+/****************************************************************
+ * 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.utils;
+
+import com.google.common.base.Preconditions;
+import org.apache.james.mailbox.exception.MailboxException;
+
+import java.util.function.BooleanSupplier;
+import java.util.stream.IntStream;
+
+public class FunctionRunnerWithRetry {
+
+ private final int maxRetry;
+
+ public FunctionRunnerWithRetry(int maxRetry) {
+ Preconditions.checkArgument(maxRetry > 0);
+ this.maxRetry = maxRetry;
+ }
+
+ public void execute(BooleanSupplier functionNotifyingSuccess) throws MailboxException {
+ IntStream.range(0, maxRetry)
+ .filter(
+ (x) -> functionNotifyingSuccess.getAsBoolean()
+ ).findFirst()
+ .orElseThrow(() -> new MailboxException("Can not execute Boolean Supplier."));
+ }
+
+}
Added: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/SimpleMailboxACLJsonConverter.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/SimpleMailboxACLJsonConverter.java?rev=1678368&view=auto
==============================================================================
--- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/SimpleMailboxACLJsonConverter.java (added)
+++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/SimpleMailboxACLJsonConverter.java Fri May 8 15:02:21 2015
@@ -0,0 +1,66 @@
+/****************************************************************
+ * 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.utils;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.KeyDeserializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import org.apache.james.mailbox.model.MailboxACL;
+import org.apache.james.mailbox.model.SimpleMailboxACL;
+
+import java.io.IOException;
+
+public class SimpleMailboxACLJsonConverter {
+
+ interface Rfc4314RightsMixIn {
+ @JsonValue
+ int getValue();
+ }
+
+ static class ACLKeyDeserializer extends KeyDeserializer {
+ @Override
+ public Object deserializeKey(String key, DeserializationContext deserializationContext ) throws IOException {
+ return new SimpleMailboxACL.SimpleMailboxACLEntryKey(key);
+ }
+ }
+
+ private static ObjectMapper objectMapper = new ObjectMapper();
+
+ static {
+ objectMapper.addMixInAnnotations(SimpleMailboxACL.Rfc4314Rights.class, Rfc4314RightsMixIn.class);
+ SimpleModule module = new SimpleModule();
+ module.addAbstractTypeMapping(MailboxACL.MailboxACLEntryKey.class, SimpleMailboxACL.SimpleMailboxACLEntryKey.class);
+ module.addAbstractTypeMapping(MailboxACL.MailboxACLRights.class, SimpleMailboxACL.Rfc4314Rights.class);
+ module.addKeyDeserializer(MailboxACL.MailboxACLEntryKey.class, new ACLKeyDeserializer());
+ objectMapper.registerModule(module);
+ }
+
+ public static String toJson(MailboxACL acl) throws JsonProcessingException {
+ return objectMapper.writeValueAsString(acl);
+ }
+
+ public static MailboxACL toACL(String jsonACLString) throws IOException {
+ return objectMapper.readValue(jsonACLString, SimpleMailboxACL.class);
+ }
+}
Added: james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraACLTable.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraACLTable.java?rev=1678368&view=auto
==============================================================================
--- james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraACLTable.java (added)
+++ james/mailbox/trunk/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraACLTable.java Fri May 8 15:02:21 2015
@@ -0,0 +1,28 @@
+/****************************************************************
+ * 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 CassandraACLTable {
+ String TABLE_NAME = "acl";
+
+ String ID = "id";
+ String ACL = "acl";
+ String VERSION = "version";
+}
Modified: james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraClusterSingleton.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraClusterSingleton.java?rev=1678368&r1=1678367&r2=1678368&view=diff
==============================================================================
--- james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraClusterSingleton.java (original)
+++ james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraClusterSingleton.java Fri May 8 15:02:21 2015
@@ -23,8 +23,6 @@ import org.cassandraunit.utils.EmbeddedC
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.datastax.driver.core.Session;
-
/**
* Class that will creates a single instance of Cassandra session.
*/
@@ -40,7 +38,7 @@ public final class CassandraClusterSingl
/**
* Builds a MiniCluster instance.
- *
+ *
* @return the {@link CassandraClusterSingleton} instance
* @throws RuntimeException
*/
@@ -66,16 +64,16 @@ public final class CassandraClusterSingl
/**
* Return a configuration for the runnning MiniCluster.
- *
+ *
* @return
*/
- public Session getConf() {
+ public CassandraSession getConf() {
return session;
}
/**
* Create a specific table.
- *
+ *
* @param tableName
* the table name
*/
@@ -94,6 +92,14 @@ public final class CassandraClusterSingl
+ "flagVersion bigint,"+ "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("acl")) {
+ session.execute("CREATE TABLE IF NOT EXISTS " + session.getLoggedKeyspace() + ".acl (id uuid PRIMARY KEY, acl text, version bigint);");
} else {
throw new NotImplementedException("We don't support the class " + tableName);
}
@@ -107,6 +113,7 @@ public final class CassandraClusterSingl
ensureTable("mailboxCounters");
ensureTable("message");
ensureTable("subscription");
+ ensureTable("acl");
}
/**
@@ -126,6 +133,7 @@ public final class CassandraClusterSingl
clearTable("mailboxCounters");
clearTable("message");
clearTable("subscription");
+ clearTable("acl");
}
}
Added: james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java?rev=1678368&view=auto
==============================================================================
--- james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java (added)
+++ james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java Fri May 8 15:02:21 2015
@@ -0,0 +1,219 @@
+/****************************************************************
+ * 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 static org.assertj.core.api.Assertions.assertThat;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
+
+import com.google.common.base.Throwables;
+import org.apache.james.mailbox.cassandra.CassandraClusterSingleton;
+import org.apache.james.mailbox.cassandra.table.CassandraACLTable;
+import org.apache.james.mailbox.exception.MailboxException;
+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.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+public class CassandraACLMapperTest {
+
+ private CassandraACLMapper cassandraACLMapper;
+ private CassandraClusterSingleton cassandra;
+ private SimpleMailbox<UUID> mailbox;
+ private int uidValidity;
+ private int maxRetry;
+ private ExecutorService executor;
+
+ @Before
+ public void setUp() {
+ cassandra = CassandraClusterSingleton.build();
+ cassandra.ensureAllTables();
+ uidValidity = 10;
+ mailbox = new SimpleMailbox<>(new MailboxPath("#private", "benwa@linagora.com", "INBOX"), uidValidity);
+ mailbox.setMailboxId(UUID.fromString("87B045A5-7657-44B7-81E8-40C2937BC9FE"));
+ maxRetry = 100;
+ cassandraACLMapper = new CassandraACLMapper(mailbox, cassandra.getConf(), maxRetry);
+ executor = Executors.newFixedThreadPool(2);
+ }
+
+ @After
+ public void tearDown() {
+ cassandra.clearAllTables();
+ executor.shutdownNow();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void creatingACLMapperWithNegativeMaxRetryShouldFail() {
+ new CassandraACLMapper(mailbox, cassandra.getConf(), -1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void creatingACLMapperWithNullMaxRetryShouldFail() {
+ new CassandraACLMapper(mailbox, cassandra.getConf(), 0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void creatingACLMapperWithNoMailboxIdShouldFail() {
+ new CassandraACLMapper(new SimpleMailbox<>(new MailboxPath("#private", "user", "name"), uidValidity), cassandra.getConf(), maxRetry);
+ }
+
+ @Test
+ public void retrieveACLWhenPresentInBaseShouldReturnCorrespondingACL() throws Exception {
+ cassandra.getConf().execute(
+ insertInto(CassandraACLTable.TABLE_NAME)
+ .value(CassandraACLTable.ID, mailbox.getMailboxId())
+ .value(CassandraACLTable.ACL, "{\"entries\":{\"bob\":64}}")
+ .value(CassandraACLTable.VERSION, 1)
+ );
+ assertThat(cassandraACLMapper.getACL())
+ .isEqualTo(
+ SimpleMailboxACL.EMPTY.union(
+ new SimpleMailboxACL.SimpleMailboxACLEntryKey("bob", MailboxACL.NameType.user, false),
+ new SimpleMailboxACL.Rfc4314Rights(SimpleMailboxACL.Rfc4314Rights.r_Read_RIGHT))
+ );
+ }
+
+ @Test
+ public void retrieveACLWhenInvalidInBaseShouldReturnEmptyACL() throws Exception {
+ cassandra.getConf().execute(
+ insertInto(CassandraACLTable.TABLE_NAME)
+ .value(CassandraACLTable.ID, mailbox.getMailboxId())
+ .value(CassandraACLTable.ACL, "{\"entries\":{\"bob\":invalid}}")
+ .value(CassandraACLTable.VERSION, 1)
+ );
+ assertThat(cassandraACLMapper.getACL()).isEqualTo(SimpleMailboxACL.EMPTY);
+ }
+
+ @Test
+ public void retrieveACLWhenNoACLStoredShouldReturnEmptyACL() {
+ assertThat(cassandraACLMapper.getACL()).isEqualTo(SimpleMailboxACL.EMPTY);
+ }
+
+ @Test
+ public void addACLWhenNoneStoredShouldReturnUpdatedACL() throws Exception {
+ SimpleMailboxACL.SimpleMailboxACLEntryKey key = new SimpleMailboxACL.SimpleMailboxACLEntryKey("bob", MailboxACL.NameType.user, false);
+ SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(new SimpleMailboxACL.SimpleMailboxACLRight('r'));
+ cassandraACLMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(key, MailboxACL.EditMode.ADD, rights));
+ assertThat(cassandraACLMapper.getACL()).isEqualTo(new SimpleMailboxACL().union(key, rights));
+ }
+
+ @Test
+ public void modifyACLWhenStoredShouldReturnUpdatedACL() throws MailboxException {
+ SimpleMailboxACL.SimpleMailboxACLEntryKey keyBob = new SimpleMailboxACL.SimpleMailboxACLEntryKey("bob", MailboxACL.NameType.user, false);
+ SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(new SimpleMailboxACL.SimpleMailboxACLRight('r'));
+ cassandraACLMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(keyBob, MailboxACL.EditMode.ADD, rights));
+ SimpleMailboxACL.SimpleMailboxACLEntryKey keyAlice = new SimpleMailboxACL.SimpleMailboxACLEntryKey("alice", MailboxACL.NameType.user, false);
+ cassandraACLMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(keyAlice, MailboxACL.EditMode.ADD, rights));
+ assertThat(cassandraACLMapper.getACL()).isEqualTo(new SimpleMailboxACL().union(keyBob, rights).union(keyAlice, rights));
+ }
+
+ @Test
+ public void removeWhenStoredShouldReturnUpdatedACL() throws MailboxException {
+ SimpleMailboxACL.SimpleMailboxACLEntryKey key = new SimpleMailboxACL.SimpleMailboxACLEntryKey("bob", MailboxACL.NameType.user, false);
+ SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(new SimpleMailboxACL.SimpleMailboxACLRight('r'));
+ cassandraACLMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(key, MailboxACL.EditMode.ADD, rights));
+ cassandraACLMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(key, MailboxACL.EditMode.REMOVE, rights));
+ assertThat(cassandraACLMapper.getACL()).isEqualTo(SimpleMailboxACL.EMPTY);
+ }
+
+ @Test
+ public void replaceForSingleKeyWithNullRightsWhenSingleKeyStoredShouldReturnEmptyACL() throws MailboxException {
+ SimpleMailboxACL.SimpleMailboxACLEntryKey key = new SimpleMailboxACL.SimpleMailboxACLEntryKey("bob", MailboxACL.NameType.user, false);
+ SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(new SimpleMailboxACL.SimpleMailboxACLRight('r'));
+ cassandraACLMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(key, MailboxACL.EditMode.ADD, rights));
+ cassandraACLMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(key, MailboxACL.EditMode.REPLACE, null));
+ assertThat(cassandraACLMapper.getACL()).isEqualTo(SimpleMailboxACL.EMPTY);
+ }
+
+ @Test
+ public void replaceWhenNotStoredShouldUpdateACLEntry() throws MailboxException {
+ SimpleMailboxACL.SimpleMailboxACLEntryKey key = new SimpleMailboxACL.SimpleMailboxACLEntryKey("bob", MailboxACL.NameType.user, false);
+ SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(new SimpleMailboxACL.SimpleMailboxACLRight('r'));
+ cassandraACLMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(key, MailboxACL.EditMode.REPLACE, rights));
+ assertThat(cassandraACLMapper.getACL()).isEqualTo(new SimpleMailboxACL().union(key, rights));
+ }
+
+ @Test
+ public void updateInvalidACLShouldBeBasedOnEmptyACL() throws Exception {
+ cassandra.getConf().execute(
+ insertInto(CassandraACLTable.TABLE_NAME)
+ .value(CassandraACLTable.ID, mailbox.getMailboxId())
+ .value(CassandraACLTable.ACL, "{\"entries\":{\"bob\":invalid}}")
+ .value(CassandraACLTable.VERSION, 1)
+ );
+ SimpleMailboxACL.SimpleMailboxACLEntryKey key = new SimpleMailboxACL.SimpleMailboxACLEntryKey("bob", MailboxACL.NameType.user, false);
+ SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(new SimpleMailboxACL.SimpleMailboxACLRight('r'));
+ cassandraACLMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(key, MailboxACL.EditMode.ADD, rights));
+ assertThat(cassandraACLMapper.getACL()).isEqualTo(new SimpleMailboxACL().union(key, rights));
+ }
+
+ @Test
+ public void twoConcurrentUpdatesWhenNoACEStoredShouldReturnACEWithTwoEntries() throws Exception {
+ CountDownLatch countDownLatch = new CountDownLatch(2);
+ SimpleMailboxACL.SimpleMailboxACLEntryKey keyBob = new SimpleMailboxACL.SimpleMailboxACLEntryKey("bob", MailboxACL.NameType.user, false);
+ SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(new SimpleMailboxACL.SimpleMailboxACLRight('r'));
+ SimpleMailboxACL.SimpleMailboxACLEntryKey keyAlice = new SimpleMailboxACL.SimpleMailboxACLEntryKey("alice", MailboxACL.NameType.user, false);
+ Future<Boolean> future1 = performACLUpdateInExecutor(executor, keyBob, rights, countDownLatch::countDown);
+ Future<Boolean> future2 = performACLUpdateInExecutor(executor, keyAlice, rights, countDownLatch::countDown);
+ awaitAll(future1, future2);
+ assertThat(cassandraACLMapper.getACL()).isEqualTo(new SimpleMailboxACL().union(keyBob, rights).union(keyAlice, rights));
+ }
+
+ @Test
+ public void twoConcurrentUpdatesWhenStoredShouldReturnACEWithTwoEntries() throws Exception {
+ CountDownLatch countDownLatch = new CountDownLatch(2);
+ SimpleMailboxACL.SimpleMailboxACLEntryKey keyBenwa = new SimpleMailboxACL.SimpleMailboxACLEntryKey("benwa", MailboxACL.NameType.user, false);
+ SimpleMailboxACL.Rfc4314Rights rights = new SimpleMailboxACL.Rfc4314Rights(new SimpleMailboxACL.SimpleMailboxACLRight('r'));
+ cassandraACLMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(keyBenwa, MailboxACL.EditMode.ADD, rights));
+ SimpleMailboxACL.SimpleMailboxACLEntryKey keyBob = new SimpleMailboxACL.SimpleMailboxACLEntryKey("bob", MailboxACL.NameType.user, false);
+ SimpleMailboxACL.SimpleMailboxACLEntryKey keyAlice = new SimpleMailboxACL.SimpleMailboxACLEntryKey("alice", MailboxACL.NameType.user, false);
+ Future<Boolean> future1 = performACLUpdateInExecutor(executor, keyBob, rights, countDownLatch::countDown);
+ Future<Boolean> future2 = performACLUpdateInExecutor(executor, keyAlice, rights, countDownLatch::countDown);
+ awaitAll(future1, future2);
+ assertThat(cassandraACLMapper.getACL()).isEqualTo(new SimpleMailboxACL().union(keyBob, rights).union(keyAlice, rights).union(keyBenwa, rights));
+ }
+
+ private void awaitAll(Future<Boolean>... futures) throws InterruptedException, java.util.concurrent.ExecutionException, java.util.concurrent.TimeoutException {
+ for (Future<Boolean> future : futures) {
+ future.get(10l, TimeUnit.SECONDS);
+ }
+ }
+
+ private Future<Boolean> performACLUpdateInExecutor(ExecutorService executor, SimpleMailboxACL.SimpleMailboxACLEntryKey key, SimpleMailboxACL.Rfc4314Rights rights, CassandraACLMapper.CodeInjector runnable) {
+ return executor.submit(() -> {
+ CassandraACLMapper aclMapper = new CassandraACLMapper(mailbox, cassandra.getConf(), maxRetry, runnable);
+ try {
+ aclMapper.updateACL(new SimpleMailboxACL.SimpleMailboxACLCommand(key, MailboxACL.EditMode.ADD, rights));
+ } catch (MailboxException exception) {
+ throw Throwables.propagate(exception);
+ }
+ return true;
+ });
+ }
+
+}
Modified: james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java?rev=1678368&r1=1678367&r2=1678368&view=diff
==============================================================================
--- james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java (original)
+++ james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java Fri May 8 15:02:21 2015
@@ -33,13 +33,12 @@ import org.apache.james.mailbox.exceptio
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.store.mail.model.Mailbox;
import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.datastax.driver.core.Session;
-
/**
* CassandraMailboxMapper unit tests.
*
@@ -47,28 +46,31 @@ import com.datastax.driver.core.Session;
public class CassandraMailboxMapperTest {
private static final Logger LOG = LoggerFactory.getLogger(CassandraMailboxMapperTest.class);
- public static final CassandraClusterSingleton CLUSTER = CassandraClusterSingleton.build();
+ public static final CassandraClusterSingleton CASSANDRA = CassandraClusterSingleton.build();
private static CassandraMailboxMapper mapper;
private static List<SimpleMailbox<UUID>> mailboxList;
private static List<MailboxPath> pathsList;
private static final int NAMESPACES = 5;
private static final int USERS = 5;
private static final int MAILBOX_NO = 5;
+ private static final int MAX_RETRY = 100;
private static final char SEPARATOR = '%';
- private Session session;
@Before
public void setUp() throws Exception {
- CLUSTER.ensureAllTables();
- CLUSTER.clearAllTables();
- session = CLUSTER.getConf();
+ CASSANDRA.ensureAllTables();
fillMailboxList();
- mapper = new CassandraMailboxMapper(session);
+ mapper = new CassandraMailboxMapper(CASSANDRA.getConf(), MAX_RETRY);
for (SimpleMailbox<UUID> mailbox : mailboxList) {
mapper.save(mailbox);
}
}
+ @After
+ public void cleanUp() {
+ CASSANDRA.clearAllTables();
+ }
+
/**
* Test an ordered scenario with list, delete... methods.
*
@@ -119,7 +121,7 @@ public class CassandraMailboxMapperTest
if (i % 2 == 0) {
newPath.setUser(null);
}
- addMailbox(new SimpleMailbox<UUID>(newPath, 1234));
+ addMailbox(new SimpleMailbox<>(newPath, 1234));
}
result = mapper.findMailboxWithPathLike(path);
assertEquals(end - start + 1, result.size());
@@ -193,7 +195,7 @@ public class CassandraMailboxMapperTest
LOG.info("hasChildren");
String oldName;
for (MailboxPath path : pathsList) {
- final SimpleMailbox<UUID> mailbox = new SimpleMailbox<UUID>(path, 12455);
+ final SimpleMailbox<UUID> mailbox = new SimpleMailbox<>(path, 12455);
oldName = mailbox.getName();
if (path.getUser().equals("user3")) {
mailbox.setName("test");
@@ -210,8 +212,8 @@ public class CassandraMailboxMapperTest
}
private static void fillMailboxList() {
- mailboxList = new ArrayList<SimpleMailbox<UUID>>();
- pathsList = new ArrayList<MailboxPath>();
+ mailboxList = new ArrayList<>();
+ pathsList = new ArrayList<>();
MailboxPath path;
String name;
for (int i = 0; i < NAMESPACES; i++) {
@@ -224,7 +226,7 @@ public class CassandraMailboxMapperTest
}
path = new MailboxPath("namespace" + i, "user" + j, name);
pathsList.add(path);
- mailboxList.add(new SimpleMailbox<UUID>(path, 13));
+ mailboxList.add(new SimpleMailbox<>(path, 13));
}
}
}
Modified: james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidAndModSeqProviderTest.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidAndModSeqProviderTest.java?rev=1678368&r1=1678367&r2=1678368&view=diff
==============================================================================
--- james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidAndModSeqProviderTest.java (original)
+++ james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraUidAndModSeqProviderTest.java Fri May 8 15:02:21 2015
@@ -27,13 +27,12 @@ import java.util.UUID;
import org.apache.james.mailbox.cassandra.CassandraClusterSingleton;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.datastax.driver.core.Session;
-
/**
* Unit tests for UidProvider and ModSeqProvider.
*
@@ -41,8 +40,7 @@ import com.datastax.driver.core.Session;
public class CassandraUidAndModSeqProviderTest {
private static final Logger LOG = LoggerFactory.getLogger(CassandraUidAndModSeqProviderTest.class);
- private static final CassandraClusterSingleton CLUSTER = CassandraClusterSingleton.build();
- private static Session session;
+ private static final CassandraClusterSingleton CASSANDRA = CassandraClusterSingleton.build();
private static CassandraUidProvider uidProvider;
private static CassandraModSeqProvider modSeqProvider;
private static CassandraMailboxMapper mapper;
@@ -51,25 +49,29 @@ public class CassandraUidAndModSeqProvid
private static final int NAMESPACES = 5;
private static final int USERS = 5;
private static final int MAILBOX_NO = 5;
+ private static final int MAX_RETRY = 100;
private static final char SEPARATOR = '%';
@Before
public void setUpClass() throws Exception {
- CLUSTER.ensureAllTables();
- CLUSTER.ensureAllTables();
- session = CLUSTER.getConf();
- uidProvider = new CassandraUidProvider(session);
- modSeqProvider = new CassandraModSeqProvider(session);
- mapper = new CassandraMailboxMapper(session);
+ CASSANDRA.ensureAllTables();
+ uidProvider = new CassandraUidProvider(CASSANDRA.getConf());
+ modSeqProvider = new CassandraModSeqProvider(CASSANDRA.getConf());
+ mapper = new CassandraMailboxMapper(CASSANDRA.getConf(), MAX_RETRY);
fillMailboxList();
for (SimpleMailbox<UUID> mailbox : mailboxList) {
mapper.save(mailbox);
}
}
+ @After
+ public void cleanUp() {
+ CASSANDRA.clearAllTables();
+ }
+
private static void fillMailboxList() {
- mailboxList = new ArrayList<SimpleMailbox<UUID>>();
- pathsList = new ArrayList<MailboxPath>();
+ mailboxList = new ArrayList<>();
+ pathsList = new ArrayList<>();
MailboxPath path;
String name;
for (int i = 0; i < NAMESPACES; i++) {
@@ -82,7 +84,7 @@ public class CassandraUidAndModSeqProvid
}
path = new MailboxPath("namespace" + i, "user" + j, name);
pathsList.add(path);
- mailboxList.add(new SimpleMailbox<UUID>(path, 13));
+ mailboxList.add(new SimpleMailbox<>(path, 13));
}
}
}
@@ -97,7 +99,7 @@ public class CassandraUidAndModSeqProvid
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 SimpleMailbox<>(path, 1234);
mapper.save(newBox);
mailboxList.add(newBox);
pathsList.add(path);
@@ -133,7 +135,7 @@ public class CassandraUidAndModSeqProvid
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 SimpleMailbox<>(path, 1234);
mapper.save(newBox);
mailboxList.add(newBox);
pathsList.add(path);
Added: james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/FunctionRunnerWithRetryTest.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/FunctionRunnerWithRetryTest.java?rev=1678368&view=auto
==============================================================================
--- james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/FunctionRunnerWithRetryTest.java (added)
+++ james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/FunctionRunnerWithRetryTest.java Fri May 8 15:02:21 2015
@@ -0,0 +1,85 @@
+/****************************************************************
+ * 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.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.commons.lang.mutable.MutableInt;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.junit.Test;
+
+public class FunctionRunnerWithRetryTest {
+
+ private final static int MAX_RETRY = 10;
+
+ @Test(expected = IllegalArgumentException.class)
+ public void functionRunnerWithInvalidMaxRetryShouldFail() throws Exception {
+ new FunctionRunnerWithRetry(-1);
+ }
+
+ @Test(expected = MailboxException.class)
+ public void functionRunnerShouldFailIfTransactionCanNotBePerformed() throws Exception {
+ final MutableInt value = new MutableInt(0);
+ new FunctionRunnerWithRetry(MAX_RETRY).execute(
+ () -> {
+ value.increment();
+ return false;
+ }
+ );
+ assertThat(value.getValue()).isEqualTo(MAX_RETRY);
+ }
+
+ @Test
+ public void functionRunnerShouldWorkOnFirstTry() throws Exception {
+ final MutableInt value = new MutableInt(0);
+ new FunctionRunnerWithRetry(MAX_RETRY).execute(
+ () -> {
+ value.increment();
+ return true;
+ }
+ );
+ assertThat(value.getValue()).isEqualTo(1);
+ }
+
+ @Test
+ public void functionRunnerShouldWorkIfNotSucceededOnFirstTry() throws Exception {
+ final MutableInt value = new MutableInt(0);
+ new FunctionRunnerWithRetry(MAX_RETRY).execute(
+ () -> {
+ value.increment();
+ return (Integer) value.getValue() == MAX_RETRY / 2;
+ }
+ );
+ assertThat(value.getValue()).isEqualTo(MAX_RETRY / 2);
+ }
+
+ @Test
+ public void functionRunnerShouldWorkIfNotSucceededOnMaxRetryReached() throws Exception {
+ final MutableInt value = new MutableInt(0);
+ new FunctionRunnerWithRetry(MAX_RETRY).execute(
+ () -> {
+ value.increment();
+ return (Integer) value.getValue() == MAX_RETRY;
+ }
+ );
+ assertThat(value.getValue()).isEqualTo(MAX_RETRY);
+ }
+
+}
Added: james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/SimpleMailboxACLJsonConverterTest.java
URL: http://svn.apache.org/viewvc/james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/SimpleMailboxACLJsonConverterTest.java?rev=1678368&view=auto
==============================================================================
--- james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/SimpleMailboxACLJsonConverterTest.java (added)
+++ james/mailbox/trunk/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/SimpleMailboxACLJsonConverterTest.java Fri May 8 15:02:21 2015
@@ -0,0 +1,119 @@
+/****************************************************************
+ * 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.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+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;
+
+public class SimpleMailboxACLJsonConverterTest {
+
+ public class ACLMapBuilder {
+ private Map<SimpleMailboxACL.MailboxACLEntryKey, MailboxACL.MailboxACLRights> map;
+
+ public ACLMapBuilder() {
+ map = new HashMap<>();
+ }
+
+ public ACLMapBuilder addSingleUserEntryToMap() {
+ 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);
+ return this;
+ }
+
+ public ACLMapBuilder addSingleSpecialEntryToMap() {
+ 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);
+ return this;
+ }
+
+ public ACLMapBuilder addSingleGroupEntryToMap() {
+ 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);
+ return this;
+ }
+
+ public MailboxACL buildAsACL() {
+ return new SimpleMailboxACL(new HashMap<>(map));
+ }
+
+ }
+
+ @Test
+ public void emptyACLShouldBeWellSerialized() throws Exception {
+ assertThat(SimpleMailboxACLJsonConverter.toJson(SimpleMailboxACL.EMPTY)).isEqualTo("{\"entries\":{}}");
+ }
+
+ @Test
+ public void singleUserEntryACLShouldBeWellSerialized() throws Exception {
+ assertThat(SimpleMailboxACLJsonConverter.toJson(new ACLMapBuilder().addSingleUserEntryToMap().buildAsACL()))
+ .isEqualTo("{\"entries\":{\"-user\":2040}}");
+ }
+
+ @Test
+ public void singleGroupEntryACLShouldBeWellSerialized() throws Exception {
+ assertThat(SimpleMailboxACLJsonConverter.toJson(new ACLMapBuilder().addSingleGroupEntryToMap().buildAsACL()))
+ .isEqualTo("{\"entries\":{\"-$group\":2032}}");
+ }
+
+ @Test
+ public void singleSpecialEntryACLShouldBeWellSerialized() throws Exception {
+ assertThat(SimpleMailboxACLJsonConverter.toJson(new ACLMapBuilder().addSingleSpecialEntryToMap().buildAsACL()))
+ .isEqualTo("{\"entries\":{\"-special\":1968}}");
+ }
+
+ @Test
+ public void multipleEntriesACLShouldBeWellSerialized() throws Exception {
+ assertThat(SimpleMailboxACLJsonConverter.toJson(new ACLMapBuilder().addSingleUserEntryToMap().addSingleGroupEntryToMap().buildAsACL()))
+ .isEqualTo("{\"entries\":{\"-user\":2040,\"-$group\":2032}}");
+ }
+
+ @Test
+ public void emptyACLShouldBeWellDeSerialized() throws Exception {
+ assertThat(SimpleMailboxACLJsonConverter.toACL("{\"entries\":{}}")).isEqualTo(SimpleMailboxACL.EMPTY);
+ }
+
+ @Test
+ public void singleUserEntryACLShouldBeWellDeSerialized() throws Exception {
+ assertThat(SimpleMailboxACLJsonConverter.toACL("{\"entries\":{\"-user\":2040}}"))
+ .isEqualTo(new ACLMapBuilder().addSingleUserEntryToMap().buildAsACL());
+ }
+
+ @Test
+ public void singleGroupEntryACLShouldBeWellDeSerialized() throws Exception {
+ assertThat(SimpleMailboxACLJsonConverter.toACL("{\"entries\":{\"-$group\":2032}}"))
+ .isEqualTo(new ACLMapBuilder().addSingleGroupEntryToMap().buildAsACL());
+ }
+
+ @Test
+ public void multipleEntriesACLShouldBeWellDeSerialized() throws Exception {
+ assertThat(SimpleMailboxACLJsonConverter.toACL("{\"entries\":{\"-user\":2040,\"-$group\":2032}}"))
+ .isEqualTo(new ACLMapBuilder().addSingleUserEntryToMap().addSingleGroupEntryToMap().buildAsACL());
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org