Author: matthieu Date: Mon Nov 2 14:15:54 2015 New Revision: 1712007 URL: http://svn.apache.org/viewvc?rev=1712007&view=rev Log: JAMES-1629 Cassandra RRT implementation
Contributed by Antoine Duprat Added: james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRRTModule.java - copied, changed from r1712006, james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/CassandraRRTModule.java james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/tables/ james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/tables/CassandraRecipientRewriteTableTable.java - copied, changed from r1712006, james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/RewriteTablesTest.java Removed: james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/CassandraRRTModule.java Modified: james/project/trunk/server/data/data-api/pom.xml james/project/trunk/server/data/data-api/src/main/java/org/apache/james/rrt/lib/Mappings.java james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTable.java james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableTest.java james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraStepdefs.java james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/RewriteTablesTest.java james/project/trunk/server/data/data-library/pom.xml james/project/trunk/server/data/data-library/src/main/java/org/apache/james/rrt/lib/MappingsImpl.java james/project/trunk/server/data/data-library/src/test/java/org/apache/james/rrt/lib/MappingsImplTest.java Modified: james/project/trunk/server/data/data-api/pom.xml URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-api/pom.xml?rev=1712007&r1=1712006&r2=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-api/pom.xml (original) +++ james/project/trunk/server/data/data-api/pom.xml Mon Nov 2 14:15:54 2015 @@ -41,6 +41,10 @@ <artifactId>apache-mailet-api</artifactId> </dependency> <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + </dependency> + <dependency> <groupId>${javax.mail.groupId}</groupId> <artifactId>${javax.mail.artifactId}</artifactId> </dependency> Modified: james/project/trunk/server/data/data-api/src/main/java/org/apache/james/rrt/lib/Mappings.java URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-api/src/main/java/org/apache/james/rrt/lib/Mappings.java?rev=1712007&r1=1712006&r2=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-api/src/main/java/org/apache/james/rrt/lib/Mappings.java (original) +++ james/project/trunk/server/data/data-api/src/main/java/org/apache/james/rrt/lib/Mappings.java Mon Nov 2 14:15:54 2015 @@ -22,6 +22,8 @@ package org.apache.james.rrt.lib; import org.apache.james.rrt.lib.Mapping.Type; +import com.google.common.base.Optional; + public interface Mappings extends Iterable<Mapping> { boolean contains(String mapping); @@ -43,5 +45,8 @@ public interface Mappings extends Iterab Mappings exclude(Type type); Mapping getError(); - + + Optional<Mappings> toOptional(); + + Mappings union(Mappings mappings); } \ No newline at end of file Copied: james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRRTModule.java (from r1712006, james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/CassandraRRTModule.java) URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRRTModule.java?p2=james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRRTModule.java&p1=james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/CassandraRRTModule.java&r1=1712006&r2=1712007&rev=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/CassandraRRTModule.java (original) +++ james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRRTModule.java Mon Nov 2 14:15:54 2015 @@ -19,6 +19,8 @@ package org.apache.james.rrt.cassandra; +import static com.datastax.driver.core.DataType.text; + import java.util.Arrays; import java.util.List; @@ -26,6 +28,10 @@ import org.apache.james.backends.cassand import org.apache.james.backends.cassandra.components.CassandraModule; import org.apache.james.backends.cassandra.components.CassandraTable; import org.apache.james.backends.cassandra.components.CassandraType; +import org.apache.james.rrt.cassandra.tables.CassandraRecipientRewriteTableTable; + +import com.datastax.driver.core.schemabuilder.SchemaBuilder; +import com.google.common.collect.ImmutableList; public class CassandraRRTModule implements CassandraModule { @@ -34,7 +40,13 @@ public class CassandraRRTModule implemen private final List<CassandraType> types; public CassandraRRTModule() { - tables = Arrays.asList(); + tables = ImmutableList.of( + new CassandraTable(CassandraRecipientRewriteTableTable.TABLE_NAME, + SchemaBuilder.createTable(CassandraRecipientRewriteTableTable.TABLE_NAME) + .ifNotExists() + .addPartitionKey(CassandraRecipientRewriteTableTable.USER, text()) + .addClusteringColumn(CassandraRecipientRewriteTableTable.DOMAIN, text()) + .addClusteringColumn(CassandraRecipientRewriteTableTable.MAPPING, text()))); index = Arrays.asList(); types = Arrays.asList(); } Modified: james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTable.java URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTable.java?rev=1712007&r1=1712006&r2=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTable.java (original) +++ james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTable.java Mon Nov 2 14:15:54 2015 @@ -18,35 +18,126 @@ ****************************************************************/ package org.apache.james.rrt.cassandra; -import java.util.Collection; +import static com.datastax.driver.core.querybuilder.QueryBuilder.delete; +import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; +import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto; +import static com.datastax.driver.core.querybuilder.QueryBuilder.select; +import static org.apache.james.rrt.cassandra.tables.CassandraRecipientRewriteTableTable.DOMAIN; +import static org.apache.james.rrt.cassandra.tables.CassandraRecipientRewriteTableTable.MAPPING; +import static org.apache.james.rrt.cassandra.tables.CassandraRecipientRewriteTableTable.TABLE_NAME; +import static org.apache.james.rrt.cassandra.tables.CassandraRecipientRewriteTableTable.USER; + +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; import org.apache.james.rrt.api.RecipientRewriteTableException; import org.apache.james.rrt.lib.AbstractRecipientRewriteTable; +import org.apache.james.rrt.lib.Mappings; +import org.apache.james.rrt.lib.MappingsImpl; + +import com.datastax.driver.core.Session; +import com.google.common.base.Optional; public class CassandraRecipientRewriteTable extends AbstractRecipientRewriteTable { + private Session session; + + @Inject + @Resource + public void setSession(@Named("cassandra-session") Session session) { + this.session = session; + } + @Override protected void addMappingInternal(String user, String domain, String mapping) throws RecipientRewriteTableException { + session.execute(insertInto(TABLE_NAME) + .value(USER, getFixedUser(user)) + .value(DOMAIN, getFixedDomain(domain)) + .value(MAPPING, mapping)); } @Override protected void removeMappingInternal(String user, String domain, String mapping) throws RecipientRewriteTableException { + session.execute(delete() + .from(TABLE_NAME) + .where(eq(USER, getFixedUser(user))) + .and(eq(DOMAIN, getFixedDomain(domain))) + .and(eq(MAPPING, mapping))); } @Override - protected Collection<String> getUserDomainMappingsInternal(String user, String domain) throws RecipientRewriteTableException { - return null; + protected Mappings getUserDomainMappingsInternal(String user, String domain) throws RecipientRewriteTableException { + return retrieveMappings(user, domain) + .orNull(); + } + + private Optional<Mappings> retrieveMappings(String user, String domain) { + List<String> mappings = session.execute(select(MAPPING) + .from(TABLE_NAME) + .where(eq(USER, getFixedUser(user))) + .and(eq(DOMAIN, getFixedDomain(domain)))) + .all() + .stream() + .map(row -> row.getString(MAPPING)) + .collect(Collectors.toList()); + + return MappingsImpl.fromCollection(mappings).toOptional(); } @Override - protected Map<String, Collection<String>> getAllMappingsInternal() throws RecipientRewriteTableException { - return null; + protected Map<String, Mappings> getAllMappingsInternal() throws RecipientRewriteTableException { + Map<String, Mappings> map = session.execute(select(USER, DOMAIN, MAPPING) + .from(TABLE_NAME)) + .all() + .stream() + .map(row -> new UserMapping(row.getString(USER), row.getString(DOMAIN), row.getString(MAPPING))) + .collect(Collectors.toMap(UserMapping::asKey, + userMapping -> MappingsImpl.fromRawString(userMapping.getMapping()), + (first, second) -> first.union(second))); + return map.isEmpty() ? null : map; + } + + private static class UserMapping { + + private final String user; + private final String domain; + private final String mapping; + + public UserMapping(String user, String domain, String mapping) { + this.user = user; + this.domain = domain; + this.mapping = mapping; + } + + public String getUser() { + return user; + } + + public String getDomain() { + return domain; + } + + public String getMapping() { + return mapping; + } + + public String asKey() { + return getUser() + "@" + getDomain(); + } } @Override protected String mapAddressInternal(String user, String domain) throws RecipientRewriteTableException { - return null; + Mappings mappings = retrieveMappings(user, domain) + .or(() -> retrieveMappings(WILDCARD, domain) + .or(() -> retrieveMappings(user, WILDCARD) + .or(MappingsImpl.empty()))); + return !mappings.isEmpty() ? mappings.serialize() : null; } } Copied: james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/tables/CassandraRecipientRewriteTableTable.java (from r1712006, james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/RewriteTablesTest.java) URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/tables/CassandraRecipientRewriteTableTable.java?p2=james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/tables/CassandraRecipientRewriteTableTable.java&p1=james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/RewriteTablesTest.java&r1=1712006&r2=1712007&rev=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/RewriteTablesTest.java (original) +++ james/project/trunk/server/data/data-cassandra/src/main/java/org/apache/james/rrt/cassandra/tables/CassandraRecipientRewriteTableTable.java Mon Nov 2 14:15:54 2015 @@ -16,20 +16,15 @@ * specific language governing permissions and limitations * * under the License. * ****************************************************************/ -package org.apache.james.rrt.cassandra; -import org.junit.Ignore; -import org.junit.runner.RunWith; +package org.apache.james.rrt.cassandra.tables; -import cucumber.api.CucumberOptions; -import cucumber.api.junit.Cucumber; -@Ignore -@RunWith(Cucumber.class) -@CucumberOptions( - features = { "classpath:cucumber/" }, - glue = { "org.apache.james.rrt.lib", "org.apache.james.rrt.cassandra" }, - tags = { "~@ignore" } - ) -public class RewriteTablesTest { +public interface CassandraRecipientRewriteTableTable { + + String TABLE_NAME = "rrt"; + + String USER = "user"; + String DOMAIN = "domain"; + String MAPPING = "mapping"; } Modified: james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableTest.java URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableTest.java?rev=1712007&r1=1712006&r2=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableTest.java (original) +++ james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraRecipientRewriteTableTest.java Mon Nov 2 14:15:54 2015 @@ -18,27 +18,90 @@ ****************************************************************/ package org.apache.james.rrt.cassandra; +import org.apache.commons.configuration.DefaultConfigurationBuilder; +import org.apache.james.backends.cassandra.CassandraClusterSingleton; import org.apache.james.rrt.api.RecipientRewriteTableException; import org.apache.james.rrt.lib.AbstractRecipientRewriteTable; import org.apache.james.rrt.lib.AbstractRecipientRewriteTableTest; -import org.junit.Ignore; +import org.slf4j.LoggerFactory; + +import cucumber.api.java.After; +import cucumber.api.java.Before; -@Ignore public class CassandraRecipientRewriteTableTest extends AbstractRecipientRewriteTableTest { + private CassandraClusterSingleton cassandra; + + @Before + @Override + public void setUp() throws Exception { + cassandra = CassandraClusterSingleton.create(new CassandraRRTModule()); + cassandra.ensureAllTables(); + super.setUp(); + } + + @After + @Override + public void tearDown() throws Exception { + super.tearDown(); + cassandra.clearAllTables(); + } + @Override protected AbstractRecipientRewriteTable getRecipientRewriteTable() throws Exception { - return null; + CassandraRecipientRewriteTable rrt = new CassandraRecipientRewriteTable(); + rrt.setSession(cassandra.getConf()); + rrt.setLog(LoggerFactory.getLogger("MockLog")); + rrt.configure(new DefaultConfigurationBuilder()); + return rrt; } @Override protected boolean addMapping(String user, String domain, String mapping, int type) throws RecipientRewriteTableException { - return false; + try { + switch (type) { + case ERROR_TYPE: + virtualUserTable.addErrorMapping(user, domain, mapping); + return true; + case REGEX_TYPE: + virtualUserTable.addRegexMapping(user, domain, mapping); + return true; + case ADDRESS_TYPE: + virtualUserTable.addAddressMapping(user, domain, mapping); + return true; + case ALIASDOMAIN_TYPE: + virtualUserTable.addAliasDomainMapping(domain, mapping); + return true; + default: + return false; + } + } catch (RecipientRewriteTableException e) { + return false; + } } @Override protected boolean removeMapping(String user, String domain, String mapping, int type) throws RecipientRewriteTableException { - return false; + try { + switch (type) { + case ERROR_TYPE: + virtualUserTable.removeErrorMapping(user, domain, mapping); + return true; + case REGEX_TYPE: + virtualUserTable.removeRegexMapping(user, domain, mapping); + return true; + case ADDRESS_TYPE: + virtualUserTable.removeAddressMapping(user, domain, mapping); + return true; + case ALIASDOMAIN_TYPE: + virtualUserTable.removeAliasDomainMapping(domain, mapping); + return true; + default: + return false; + } + } catch (RecipientRewriteTableException e) { + return false; + } } } Modified: james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraStepdefs.java URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraStepdefs.java?rev=1712007&r1=1712006&r2=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraStepdefs.java (original) +++ james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/CassandraStepdefs.java Mon Nov 2 14:15:54 2015 @@ -51,6 +51,7 @@ public class CassandraStepdefs { private AbstractRecipientRewriteTable getRecipientRewriteTable() throws Exception { CassandraRecipientRewriteTable rrt = new CassandraRecipientRewriteTable(); + rrt.setSession(cassandra.getConf()); rrt.setLog(LoggerFactory.getLogger("MockLog")); rrt.configure(new DefaultConfigurationBuilder()); return rrt; Modified: james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/RewriteTablesTest.java URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/RewriteTablesTest.java?rev=1712007&r1=1712006&r2=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/RewriteTablesTest.java (original) +++ james/project/trunk/server/data/data-cassandra/src/test/java/org/apache/james/rrt/cassandra/RewriteTablesTest.java Mon Nov 2 14:15:54 2015 @@ -18,18 +18,15 @@ ****************************************************************/ package org.apache.james.rrt.cassandra; -import org.junit.Ignore; import org.junit.runner.RunWith; import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber; -@Ignore @RunWith(Cucumber.class) @CucumberOptions( features = { "classpath:cucumber/" }, - glue = { "org.apache.james.rrt.lib", "org.apache.james.rrt.cassandra" }, - tags = { "~@ignore" } + glue = { "org.apache.james.rrt.lib", "org.apache.james.rrt.cassandra" } ) public class RewriteTablesTest { } Modified: james/project/trunk/server/data/data-library/pom.xml URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-library/pom.xml?rev=1712007&r1=1712006&r2=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-library/pom.xml (original) +++ james/project/trunk/server/data/data-library/pom.xml Mon Nov 2 14:15:54 2015 @@ -99,7 +99,8 @@ </dependency> <dependency> <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> + <artifactId>assertj-guava</artifactId> + <version>1.3.1</version> <scope>test</scope> </dependency> <dependency> Modified: james/project/trunk/server/data/data-library/src/main/java/org/apache/james/rrt/lib/MappingsImpl.java URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-library/src/main/java/org/apache/james/rrt/lib/MappingsImpl.java?rev=1712007&r1=1712006&r2=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-library/src/main/java/org/apache/james/rrt/lib/MappingsImpl.java (original) +++ james/project/trunk/server/data/data-library/src/main/java/org/apache/james/rrt/lib/MappingsImpl.java Mon Nov 2 14:15:54 2015 @@ -30,6 +30,7 @@ import org.apache.james.rrt.lib.Mapping. import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Objects; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; @@ -79,7 +80,7 @@ public class MappingsImpl implements Map builder.addAll(from); return builder; } - + public static Builder builder() { return new Builder(); } @@ -199,12 +200,26 @@ public class MappingsImpl implements Map Preconditions.checkState(!errors.isEmpty()); return Iterables.getFirst(errors, null); } - + + @Override + public Optional<Mappings> toOptional() { + if (isEmpty()) { + return Optional.absent(); + } + return Optional.<Mappings> of(this); + } + + @Override + public Mappings union(Mappings mappings) { + Preconditions.checkState(mappings != null, "mappings is mandatory"); + return from(this).addAll(mappings).build(); + } + @Override public int hashCode() { return Objects.hashCode(mappings); } - + @Override public boolean equals(Object obj) { if (obj instanceof MappingsImpl) { @@ -213,11 +228,9 @@ public class MappingsImpl implements Map } return false; } - + @Override public String toString() { return Objects.toStringHelper(getClass()).add("mappings", mappings).toString(); } - - } \ No newline at end of file Modified: james/project/trunk/server/data/data-library/src/test/java/org/apache/james/rrt/lib/MappingsImplTest.java URL: http://svn.apache.org/viewvc/james/project/trunk/server/data/data-library/src/test/java/org/apache/james/rrt/lib/MappingsImplTest.java?rev=1712007&r1=1712006&r2=1712007&view=diff ============================================================================== --- james/project/trunk/server/data/data-library/src/test/java/org/apache/james/rrt/lib/MappingsImplTest.java (original) +++ james/project/trunk/server/data/data-library/src/test/java/org/apache/james/rrt/lib/MappingsImplTest.java Mon Nov 2 14:15:54 2015 @@ -21,9 +21,12 @@ package org.apache.james.rrt.lib; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.guava.api.Assertions.assertThat; import org.junit.Test; +import com.google.common.base.Optional; + public class MappingsImplTest { @@ -217,4 +220,37 @@ public class MappingsImplTest { MappingsImpl mappings = MappingsImpl.builder().add(MappingImpl.regex("toto")).build(); assertThat(mappings.exclude((Mapping.Type)null)); } + + @Test + public void toOptionalShouldBePresentWhenContainingData() { + MappingsImpl mappings = MappingsImpl.builder().add("toto").build(); + + Optional<Mappings> optional = mappings.toOptional(); + assertThat(optional).isPresent(); + } + + @Test + public void toOptionalShouldBeAbsentWhenNoData() { + MappingsImpl mappings = MappingsImpl.empty(); + + Optional<Mappings> optional = mappings.toOptional(); + assertThat(optional).isAbsent(); + } + + @Test(expected=IllegalStateException.class) + public void unionShouldThrowWhenMappingsNull() { + MappingsImpl.empty().union(null); + } + + @Test + public void unionShouldReturnEmptyWhenBothEmpty() { + Mappings mappings = MappingsImpl.empty().union(MappingsImpl.empty()); + assertThat(mappings).isEmpty(); + } + + @Test + public void unionShouldReturnMergedWhenBothContainsData() { + Mappings mappings = MappingsImpl.fromRawString("toto").union(MappingsImpl.fromRawString("tata")); + assertThat(mappings).containsExactly(MappingImpl.address("toto"),MappingImpl.address("tata")); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org