From a503963c713ed219fbc2c671a5546f8bd09b6e43 Mon Sep 17 00:00:00 2001 From: Matthew Adams Date: Tue, 7 Jan 2014 12:20:37 -0600 Subject: [PATCH] DATACASS-55: WIP: all working ok --- .../config/CassandraClusterFactoryBean.java | 96 +++++++------ .../config/CassandraSessionFactoryBean.java | 89 ++++++++---- .../cassandra/config/KeyspaceAttributes.java | 53 +++++++ ...ractCassandraFactoryBeanConfiguration.java | 134 ++++++++++++++++++ .../config/xml/CassandraSessionParser.java | 33 ++++- .../cassandra/core/util/MapBuilder.java | 16 ++- .../cassandra/config/spring-cassandra-1.0.xsd | 21 +++ .../config/java/AbstractIntegrationTest.java | 2 +- ...AbstractKeyspaceCreatingConfiguration.java | 19 --- .../config/java/KeyspaceCreatingConfig.java | 14 -- .../java/KeyspaceCreatingConfigTest.java | 14 -- .../java/KeyspaceCreatingJavaConfig.java | 32 +++++ .../java/KeyspaceCreatingJavaConfigTest.java | 31 ++++ .../CreateKeyspaceCqlGeneratorTests.java | 42 +++--- .../src/test/resources/logback-test.xml | 4 +- 15 files changed, 450 insertions(+), 150 deletions(-) create mode 100644 spring-cassandra/src/main/java/org/springframework/cassandra/config/java/AbstractCassandraFactoryBeanConfiguration.java delete mode 100644 spring-cassandra/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingConfig.java delete mode 100644 spring-cassandra/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingConfigTest.java create mode 100644 spring-cassandra/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingJavaConfig.java create mode 100644 spring-cassandra/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingJavaConfigTest.java diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/CassandraClusterFactoryBean.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/CassandraClusterFactoryBean.java index ab23504a1..cdd63f6c4 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/CassandraClusterFactoryBean.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/CassandraClusterFactoryBean.java @@ -55,62 +55,50 @@ import com.datastax.driver.core.policies.RetryPolicy; public class CassandraClusterFactoryBean implements FactoryBean, InitializingBean, DisposableBean, PersistenceExceptionTranslator { - protected static final Logger log = LoggerFactory.getLogger(CassandraClusterFactoryBean.class); + public static final String DEFAULT_CONTACT_POINTS = "localhost"; + public static final boolean DEFAULT_METRICS_ENABLED = true; + public static final int DEFAULT_PORT = 9042; - private static final int DEFAULT_PORT = 9042; + protected static final Logger log = LoggerFactory.getLogger(CassandraClusterFactoryBean.class); private Cluster cluster; - private String contactPoints; - private int port = DEFAULT_PORT; + /** + * Comma-delimited string of servers. + */ + private String contactPoints = DEFAULT_CONTACT_POINTS; + private int port = CassandraClusterFactoryBean.DEFAULT_PORT; private CompressionType compressionType; - private PoolingOptionsConfig localPoolingOptions; private PoolingOptionsConfig remotePoolingOptions; private SocketOptionsConfig socketOptions; - private AuthProvider authProvider; private LoadBalancingPolicy loadBalancingPolicy; private ReconnectionPolicy reconnectionPolicy; private RetryPolicy retryPolicy; - - private boolean metricsEnabled = true; - - private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator(); - + private boolean metricsEnabled = DEFAULT_METRICS_ENABLED; private List keyspaceCreations = new ArrayList(); private List keyspaceDrops = new ArrayList(); - private List startupScripts = new ArrayList(); private List shutdownScripts = new ArrayList(); + private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator(); + @Override public Cluster getObject() throws Exception { return cluster; } - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.FactoryBean#getObjectType() - */ @Override public Class getObjectType() { return Cluster.class; } - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.FactoryBean#isSingleton() - */ @Override public boolean isSingleton() { return true; } - /* - * (non-Javadoc) - * @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException) - */ @Override public DataAccessException translateExceptionIfPossible(RuntimeException ex) { return exceptionTranslator.translateExceptionIfPossible(ex); @@ -163,44 +151,56 @@ public class CassandraClusterFactoryBean implements FactoryBean, Initia builder.withoutMetrics(); } - Cluster cluster = builder.build(); - - // initialize property - this.cluster = cluster; - + cluster = builder.build(); executeSpecsAndScripts(keyspaceCreations, startupScripts); } protected void executeSpecsAndScripts(@SuppressWarnings("rawtypes") List specs, List scripts) { + Session system = null; + CassandraTemplate template = null; + try { - system = specs.size() > 0 ? cluster.connect() : null; - CassandraTemplate template = system == null ? null : new CassandraTemplate(system); + if (specs != null) { + system = specs.size() == 0 ? null : cluster.connect(); + template = system == null ? null : new CassandraTemplate(system); - Iterator i = specs.iterator(); - while (i.hasNext()) { - KeyspaceNameSpecification spec = (KeyspaceNameSpecification) i.next(); - String cql = (spec instanceof CreateKeyspaceSpecification) ? new CreateKeyspaceCqlGenerator( - (CreateKeyspaceSpecification) spec).toCql() - : new DropKeyspaceCqlGenerator((DropKeyspaceSpecification) spec).toCql(); + Iterator i = specs.iterator(); + while (i.hasNext()) { + KeyspaceNameSpecification spec = (KeyspaceNameSpecification) i.next(); + String cql = (spec instanceof CreateKeyspaceSpecification) ? new CreateKeyspaceCqlGenerator( + (CreateKeyspaceSpecification) spec).toCql() : new DropKeyspaceCqlGenerator( + (DropKeyspaceSpecification) spec).toCql(); - if (log.isDebugEnabled()) { - log.info("executing CQL [{}]", cql); + if (log.isInfoEnabled()) { + log.info("executing CQL [{}]", cql); + } + + template.execute(cql); } - - template.execute(cql); } - for (String script : startupScripts) { + if (scripts != null) { - if (log.isDebugEnabled()) { - log.info("executing raw CQL [{}]", script); + if (system == null) { + system = scripts.size() == 0 ? null : cluster.connect(); } - template.execute(script); - } + if (template == null) { + template = system == null ? null : new CassandraTemplate(system); + } + for (String script : scripts) { + + if (log.isInfoEnabled()) { + log.info("executing raw CQL [{}]", script); + } + + template.execute(script); + } + } } finally { + if (system != null) { system.shutdown(); } @@ -211,10 +211,12 @@ public class CassandraClusterFactoryBean implements FactoryBean, Initia public void destroy() throws Exception { executeSpecsAndScripts(keyspaceDrops, shutdownScripts); - cluster.shutdown(); } + /** + * Sets a comma-delimited string of the contact points (hosts) to connect to. + */ public void setContactPoints(String contactPoints) { this.contactPoints = contactPoints; } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/CassandraSessionFactoryBean.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/CassandraSessionFactoryBean.java index 2a5168db7..ecc900e2e 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/CassandraSessionFactoryBean.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/CassandraSessionFactoryBean.java @@ -15,14 +15,19 @@ */ package org.springframework.cassandra.config; +import java.util.ArrayList; +import java.util.List; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.cassandra.core.CassandraTemplate; import org.springframework.cassandra.support.CassandraExceptionTranslator; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; import com.datastax.driver.core.Cluster; @@ -41,69 +46,101 @@ public class CassandraSessionFactoryBean implements FactoryBean, Initia private static final Logger log = LoggerFactory.getLogger(CassandraSessionFactoryBean.class); - public static final String DEFAULT_REPLICATION_STRATEGY = "SimpleStrategy"; - public static final int DEFAULT_REPLICATION_FACTOR = 1; - private Cluster cluster; private Session session; private String keyspaceName; - + private List startupScripts = new ArrayList(); + private List shutdownScripts = new ArrayList(); private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator(); + @Override public Session getObject() { return session; } - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.FactoryBean#getObjectType() - */ + @Override public Class getObjectType() { return Session.class; } - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.FactoryBean#isSingleton() - */ + @Override public boolean isSingleton() { return true; } - /* - * (non-Javadoc) - * @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException) - */ + @Override public DataAccessException translateExceptionIfPossible(RuntimeException ex) { return exceptionTranslator.translateExceptionIfPossible(ex); } - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - */ + @Override public void afterPropertiesSet() throws Exception { if (cluster == null) { throw new IllegalArgumentException("at least one cluster is required"); } - this.session = StringUtils.hasText(this.keyspaceName) ? cluster.connect(keyspaceName) : cluster.connect(); + session = StringUtils.hasText(keyspaceName) ? cluster.connect(keyspaceName) : cluster.connect(); + executeScripts(startupScripts); } - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.DisposableBean#destroy() + /** + * Executes given scripts. Session must be connected when this method is called. */ - public void destroy() throws Exception { - this.session.shutdown(); + protected void executeScripts(List scripts) { + + if (scripts == null) { + return; + } + + CassandraTemplate template = new CassandraTemplate(session); + + for (String script : scripts) { + + if (log.isInfoEnabled()) { + log.info("executing raw CQL [{}]", script); + } + + template.execute(script); + } } + @Override + public void destroy() throws Exception { + + executeScripts(shutdownScripts); + session.shutdown(); + } + + /** + * Sets the keyspace name to connect to. Using null, empty string, or only whitespace will cause the + * system keyspace to be used. + */ public void setKeyspaceName(String keyspaceName) { this.keyspaceName = keyspaceName; } + /** + * Sets the cluster to use. Must not be null. + */ public void setCluster(Cluster cluster) { + if (cluster == null) { + throw new IllegalArgumentException("cluster must not be null"); + } this.cluster = cluster; } + + /** + * Sets CQL scripts to be executed immediately after the session is connected. + */ + public void setStartupScripts(List scripts) { + this.startupScripts = scripts; + } + + /** + * Sets CQL scripts to be executed immediately before the session is shutdown. + */ + public void setShutdownScripts(List scripts) { + this.shutdownScripts = scripts; + } } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/KeyspaceAttributes.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/KeyspaceAttributes.java index c8081202c..2f5e07303 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/KeyspaceAttributes.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/KeyspaceAttributes.java @@ -18,6 +18,11 @@ package org.springframework.cassandra.config; import java.util.HashMap; import java.util.Map; +import org.springframework.cassandra.core.keyspace.DefaultOption; +import org.springframework.cassandra.core.keyspace.KeyspaceOption; +import org.springframework.cassandra.core.keyspace.Option; +import org.springframework.cassandra.core.util.MapBuilder; + /** * Keyspace attributes. * @@ -33,6 +38,54 @@ public class KeyspaceAttributes { public static final long DEFAULT_REPLICATION_FACTOR = 1; public static final boolean DEFAULT_DURABLE_WRITES = true; + /** + * Returns a map of {@link Option}s suitable as the value of a {@link KeyspaceOption#REPLICATION} option with + * replication strategy class "SimpleStrategy" and with a replication factor of one. + */ + public static Map newSimpleReplication() { + return newSimpleReplication(DEFAULT_REPLICATION_FACTOR); + } + + /** + * Returns a map of {@link Option}s suitable as the value of a {@link KeyspaceOption#REPLICATION} option with + * replication strategy class "SimpleStrategy" and with a replication factor equal to that given. + */ + public static Map newSimpleReplication(long replicationFactor) { + return MapBuilder.map(Option.class, Object.class) + .entry(new DefaultOption("class", String.class, true, false, true), SIMPLE_REPLICATION_STRATEGY) + .entry(new DefaultOption("replication_factor", Long.class, true, false, false), replicationFactor).build(); + } + + /** + * Returns a map of {@link Option}s suitable as the value of a {@link KeyspaceOption#REPLICATION} option with + * replication strategy class "NetworkTopologyStrategy" and with data centers each with their corresponding + * replication factors. + */ + public static Map newNetworkReplication(DataCenterReplication... dataCenterReplications) { + + MapBuilder builder = MapBuilder.map(Option.class, Object.class).entry( + new DefaultOption("class", String.class, true, false, true), NETWORK_TOPOLOGY_REPLICATION_STRATEGY); + + for (DataCenterReplication dcr : dataCenterReplications) { + builder.entry(new DefaultOption(dcr.dataCenter, Long.class, true, false, false), dcr.replicationFactor); + } + + return builder.build(); + } + + /** + * Simple data structure to be used when setting the replication factor for a given data center. + */ + public static class DataCenterReplication { + public String dataCenter; + public long replicationFactor; + + public DataCenterReplication(String dataCenter, long replicationFactor) { + this.dataCenter = dataCenter; + this.replicationFactor = replicationFactor; + } + } + private String replicationStrategy = DEFAULT_REPLICATION_STRATEGY; private long replicationFactor = DEFAULT_REPLICATION_FACTOR; private boolean durableWrites = DEFAULT_DURABLE_WRITES; diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/java/AbstractCassandraFactoryBeanConfiguration.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/java/AbstractCassandraFactoryBeanConfiguration.java new file mode 100644 index 000000000..dbac2993e --- /dev/null +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/java/AbstractCassandraFactoryBeanConfiguration.java @@ -0,0 +1,134 @@ +package org.springframework.cassandra.config.java; + +import java.util.Collections; +import java.util.List; + +import org.springframework.cassandra.config.CassandraClusterFactoryBean; +import org.springframework.cassandra.config.CassandraSessionFactoryBean; +import org.springframework.cassandra.config.CompressionType; +import org.springframework.cassandra.config.PoolingOptionsConfig; +import org.springframework.cassandra.config.SocketOptionsConfig; +import org.springframework.cassandra.core.CassandraOperations; +import org.springframework.cassandra.core.CassandraTemplate; +import org.springframework.cassandra.core.keyspace.CreateKeyspaceSpecification; +import org.springframework.cassandra.core.keyspace.DropKeyspaceSpecification; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.datastax.driver.core.AuthProvider; +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.policies.LoadBalancingPolicy; +import com.datastax.driver.core.policies.ReconnectionPolicy; +import com.datastax.driver.core.policies.RetryPolicy; + +/** + * Base class for Spring Cassandra configuration that can handle creating namespaces, execute arbitrary CQL on startup & + * shutdown, and optionally drop namespaces. + * + * @author Matthew T. Adams + */ +@Configuration +public abstract class AbstractCassandraFactoryBeanConfiguration { + + protected abstract String getKeyspaceName(); + + @Bean + public CassandraClusterFactoryBean cluster() throws Exception { + + CassandraClusterFactoryBean bean = new CassandraClusterFactoryBean(); + bean.setAuthProvider(getAuthProvider()); + bean.setCompressionType(getCompressionType()); + bean.setContactPoints(getContactPoints()); + bean.setKeyspaceCreations(getKeyspaceCreations()); + bean.setKeyspaceDrops(getKeyspaceDrops()); + bean.setLoadBalancingPolicy(getLoadBalancingPolicy()); + bean.setLocalPoolingOptions(getLocalPoolingOptions()); + bean.setMetricsEnabled(getMetricsEnabled()); + bean.setPort(getPort()); + bean.setReconnectionPolicy(getReconnectionPolicy()); + bean.setRemotePoolingOptions(getRemotePoolingOptions()); + bean.setRetryPolicy(getRetryPolicy()); + bean.setShutdownScripts(getShutdownScripts()); + bean.setSocketOptions(getSocketOptions()); + bean.setStartupScripts(getStartupScripts()); + + return bean; + } + + @Bean + public CassandraSessionFactoryBean session() throws Exception { + + Cluster cluster = cluster().getObject(); + + CassandraSessionFactoryBean bean = new CassandraSessionFactoryBean(); + bean.setCluster(cluster); + bean.setKeyspaceName(getKeyspaceName()); + + return bean; + } + + @Bean + public CassandraOperations template() throws Exception { + return new CassandraTemplate(session().getObject()); + } + + protected List getStartupScripts() { + return Collections.emptyList(); + } + + protected SocketOptionsConfig getSocketOptions() { + return null; + } + + protected List getShutdownScripts() { + return Collections.emptyList(); + } + + protected ReconnectionPolicy getReconnectionPolicy() { + return null; + } + + protected RetryPolicy getRetryPolicy() { + return null; + } + + protected PoolingOptionsConfig getRemotePoolingOptions() { + return null; + } + + protected int getPort() { + return CassandraClusterFactoryBean.DEFAULT_PORT; + } + + protected boolean getMetricsEnabled() { + return CassandraClusterFactoryBean.DEFAULT_METRICS_ENABLED; + } + + protected PoolingOptionsConfig getLocalPoolingOptions() { + return null; + } + + protected LoadBalancingPolicy getLoadBalancingPolicy() { + return null; + } + + protected List getKeyspaceDrops() { + return Collections.emptyList(); + } + + protected List getKeyspaceCreations() { + return Collections.emptyList(); + } + + protected String getContactPoints() { + return CassandraClusterFactoryBean.DEFAULT_CONTACT_POINTS; + } + + protected CompressionType getCompressionType() { + return null; + } + + protected AuthProvider getAuthProvider() { + return null; + } +} diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraSessionParser.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraSessionParser.java index 7b8c05d92..aa73c1b77 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraSessionParser.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraSessionParser.java @@ -15,6 +15,9 @@ */ package org.springframework.cassandra.config.xml; +import java.util.ArrayList; +import java.util.List; + import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -23,6 +26,7 @@ import org.springframework.beans.factory.xml.ParserContext; import org.springframework.cassandra.config.CassandraSessionFactoryBean; import org.springframework.util.StringUtils; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; /** * Parser for <session> definitions. @@ -38,10 +42,6 @@ public class CassandraSessionParser extends AbstractSimpleBeanDefinitionParser { return CassandraSessionFactoryBean.class; } - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext) - */ @Override protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { @@ -64,5 +64,30 @@ public class CassandraSessionParser extends AbstractSimpleBeanDefinitionParser { clusterRef = BeanNames.CASSANDRA_CLUSTER; } builder.addPropertyReference("cluster", clusterRef); + + parseChildElements(element, builder); + } + + protected void parseChildElements(Element element, BeanDefinitionBuilder builder) { + + List scripts = parseScripts(element, "startup-cql"); + builder.addPropertyValue("startupScripts", scripts); + + scripts = parseScripts(element, "shutdown-cql"); + builder.addPropertyValue("shutdownScripts", scripts); + } + + protected List parseScripts(Element element, String elementName) { + + NodeList nodes = element.getElementsByTagName("startup-cql"); + int length = nodes.getLength(); + List scripts = new ArrayList(length); + + for (int i = 0; i < length; i++) { + Element script = (Element) nodes.item(i); + scripts.add(script.getTextContent()); + } + + return scripts; } } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/core/util/MapBuilder.java b/spring-cassandra/src/main/java/org/springframework/cassandra/core/util/MapBuilder.java index c09900a82..dd999d137 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/core/util/MapBuilder.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/core/util/MapBuilder.java @@ -22,7 +22,7 @@ import java.util.Set; /** * Builder for maps, which also conveniently implements {@link Map} via delegation for convenience so you don't have to - * actually {@link #build()} it (or forget to). + * actually {@link #build()} it. * * @author Matthew T. Adams * @param The key type of the map. @@ -83,58 +83,72 @@ public class MapBuilder implements Map { return new LinkedHashMap(map); } + @Override public int size() { return map.size(); } + @Override public boolean isEmpty() { return map.isEmpty(); } + @Override public boolean containsKey(Object key) { return map.containsKey(key); } + @Override public boolean containsValue(Object value) { return map.containsValue(value); } + @Override public V get(Object key) { return map.get(key); } + @Override public V put(K key, V value) { return map.put(key, value); } + @Override public V remove(Object key) { return map.remove(key); } + @Override public void putAll(Map m) { map.putAll(m); } + @Override public void clear() { map.clear(); } + @Override public Set keySet() { return map.keySet(); } + @Override public Collection values() { return map.values(); } + @Override public Set> entrySet() { return map.entrySet(); } + @Override public boolean equals(Object o) { return map.equals(o); } + @Override public int hashCode() { return map.hashCode(); } diff --git a/spring-cassandra/src/main/resources/org/springframework/cassandra/config/spring-cassandra-1.0.xsd b/spring-cassandra/src/main/resources/org/springframework/cassandra/config/spring-cassandra-1.0.xsd index 3caaeca02..c0b1ab354 100644 --- a/spring-cassandra/src/main/resources/org/springframework/cassandra/config/spring-cassandra-1.0.xsd +++ b/spring-cassandra/src/main/resources/org/springframework/cassandra/config/spring-cassandra-1.0.xsd @@ -337,6 +337,27 @@ Sets the SO_SNDBUF socket option. + + + + + + + + + + + + + + + getKeyspaceCreations() { + ArrayList list = new ArrayList(); + + CreateKeyspaceSpecification specification = CreateKeyspaceSpecification.createKeyspace().name(getKeyspaceName()); + specification.with(KeyspaceOption.REPLICATION, KeyspaceAttributes.newSimpleReplication(1L)); + + list.add(specification); + return list; + } +} diff --git a/spring-cassandra/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingJavaConfigTest.java b/spring-cassandra/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingJavaConfigTest.java new file mode 100644 index 000000000..0f639ec57 --- /dev/null +++ b/spring-cassandra/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingJavaConfigTest.java @@ -0,0 +1,31 @@ +package org.springframework.cassandra.test.integration.config.java; + +import javax.inject.Inject; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.cassandra.test.integration.config.IntegrationTestUtils; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.datastax.driver.core.Session; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = KeyspaceCreatingJavaConfig.class) +public class KeyspaceCreatingJavaConfigTest extends AbstractIntegrationTest { + + @Inject + protected Session session; + + @Override + protected String keyspace() { + return null; + } + + @Test + public void test() { + Assert.assertNotNull(session); + IntegrationTestUtils.assertKeyspaceExists(KeyspaceCreatingJavaConfig.KEYSPACE_NAME, session); + } +} diff --git a/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/CreateKeyspaceCqlGeneratorTests.java b/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/CreateKeyspaceCqlGeneratorTests.java index 93b350d43..6de52762b 100644 --- a/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/CreateKeyspaceCqlGeneratorTests.java +++ b/spring-cassandra/src/test/java/org/springframework/cassandra/test/unit/core/cql/generator/CreateKeyspaceCqlGeneratorTests.java @@ -6,6 +6,7 @@ import java.util.HashMap; import java.util.Map; import org.junit.Test; +import org.springframework.cassandra.config.KeyspaceAttributes; import org.springframework.cassandra.core.cql.generator.CreateKeyspaceCqlGenerator; import org.springframework.cassandra.core.keyspace.CreateKeyspaceSpecification; import org.springframework.cassandra.core.keyspace.DefaultOption; @@ -23,9 +24,10 @@ public class CreateKeyspaceCqlGeneratorTests { private static void assertReplicationMap(Map replicationMap, String cql) { assertTrue(cql.contains(" WITH replication = { ")); - - for (Map.Entry entry : replicationMap.entrySet() ) { - String keyValuePair = "'" + entry.getKey().getName() + "' : '" + entry.getValue().toString() + "'"; + + for (Map.Entry entry : replicationMap.entrySet()) { + String keyValuePair = "'" + entry.getKey().getName() + "' : " + (entry.getKey().quotesValue() ? "'" : "") + + entry.getValue().toString() + (entry.getKey().quotesValue() ? "'" : ""); assertTrue(cql.contains(keyValuePair)); } } @@ -41,6 +43,7 @@ public class CreateKeyspaceCqlGeneratorTests { public static abstract class CreateKeyspaceTest extends KeyspaceOperationCqlGeneratorTest { + @Override public CreateKeyspaceCqlGenerator generator() { return new CreateKeyspaceCqlGenerator(specification); } @@ -50,20 +53,15 @@ public class CreateKeyspaceCqlGeneratorTests { public String name = "mykeyspace"; public Boolean durableWrites = true; - - public Map replicationMap = new HashMap(); + + public Map replicationMap = KeyspaceAttributes.newSimpleReplication(); @Override public CreateKeyspaceSpecification specification() { keyspace = name; - - replicationMap.put( new DefaultOption( "class", String.class, false, false, true ), "SimpleStrategy" ); - replicationMap.put( new DefaultOption( "replication_factor", Long.class, false, false, true ), 1 ); - - return (CreateKeyspaceSpecification) CreateKeyspaceSpecification.createKeyspace() - .name(keyspace) - .with(KeyspaceOption.REPLICATION, replicationMap) - .with(KeyspaceOption.DURABLE_WRITES, durableWrites); + + return CreateKeyspaceSpecification.createKeyspace().name(keyspace) + .with(KeyspaceOption.REPLICATION, replicationMap).with(KeyspaceOption.DURABLE_WRITES, durableWrites); } @Test @@ -80,21 +78,19 @@ public class CreateKeyspaceCqlGeneratorTests { public String name = "mykeyspace"; public Boolean durableWrites = false; - + public Map replicationMap = new HashMap(); @Override public CreateKeyspaceSpecification specification() { keyspace = name; - - replicationMap.put( new DefaultOption( "class", String.class, false, false, true ), "NetworkTopologyStrategy" ); - replicationMap.put( new DefaultOption( "dc1", Long.class, false, false, true ), 2 ); - replicationMap.put( new DefaultOption( "dc2", Long.class, false, false, true ), 3 ); - - return (CreateKeyspaceSpecification) CreateKeyspaceSpecification.createKeyspace() - .name(keyspace) - .with(KeyspaceOption.REPLICATION, replicationMap) - .with(KeyspaceOption.DURABLE_WRITES, durableWrites); + + replicationMap.put(new DefaultOption("class", String.class, false, false, true), "NetworkTopologyStrategy"); + replicationMap.put(new DefaultOption("dc1", Long.class, false, false, true), 2); + replicationMap.put(new DefaultOption("dc2", Long.class, false, false, true), 3); + + return CreateKeyspaceSpecification.createKeyspace().name(keyspace) + .with(KeyspaceOption.REPLICATION, replicationMap).with(KeyspaceOption.DURABLE_WRITES, durableWrites); } @Test diff --git a/spring-cassandra/src/test/resources/logback-test.xml b/spring-cassandra/src/test/resources/logback-test.xml index 38a367981..7db55523f 100644 --- a/spring-cassandra/src/test/resources/logback-test.xml +++ b/spring-cassandra/src/test/resources/logback-test.xml @@ -9,8 +9,10 @@ + - + +