diff --git a/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java b/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java index f183ffca6..6b0fe1029 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java @@ -22,6 +22,7 @@ import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; @@ -49,12 +50,15 @@ import com.datastax.driver.core.QueryOptions; import com.datastax.driver.core.SSLOptions; import com.datastax.driver.core.Session; import com.datastax.driver.core.SocketOptions; +import com.datastax.driver.core.TimestampGenerator; +import com.datastax.driver.core.policies.AddressTranslator; import com.datastax.driver.core.policies.LoadBalancingPolicy; import com.datastax.driver.core.policies.ReconnectionPolicy; import com.datastax.driver.core.policies.RetryPolicy; +import com.datastax.driver.core.policies.SpeculativeExecutionPolicy; /** - * Convenient {@link org.springframework.beans.factory.FactoryBean} for configuring a Cassandra {@link Cluster}. + * {@link org.springframework.beans.factory.FactoryBean} for configuring a Cassandra {@link Cluster}. * * @author Alex Shvid * @author Matthew T. Adams @@ -69,164 +73,171 @@ import com.datastax.driver.core.policies.RetryPolicy; * @see org.springframework.beans.factory.FactoryBean * @see com.datastax.driver.core.Cluster */ -public class CassandraCqlClusterFactoryBean - implements FactoryBean, InitializingBean, DisposableBean, PersistenceExceptionTranslator { +@SuppressWarnings("unused") +public class CassandraCqlClusterFactoryBean implements FactoryBean, InitializingBean, DisposableBean, + BeanNameAware, PersistenceExceptionTranslator { + + public static final boolean DEFAULT_JMX_REPORTING_ENABLED = true; + public static final boolean DEFAULT_METRICS_ENABLED = true; + public static final boolean DEFAULT_SSL_ENABLED = false; + + public static final int DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS = 10; + public static final int DEFAULT_PORT = 9042; public static final String DEFAULT_CONTACT_POINTS = "localhost"; - public static final boolean DEFAULT_METRICS_ENABLED = true; - public static final boolean DEFAULT_JMX_REPORTING_ENABLED = true; - public static final boolean DEFAULT_SSL_ENABLED = false; - public static final int DEFAULT_PORT = 9042; protected static final Logger log = LoggerFactory.getLogger(CassandraCqlClusterFactoryBean.class); + private boolean jmxReportingEnabled = DEFAULT_JMX_REPORTING_ENABLED; + private boolean metricsEnabled = DEFAULT_METRICS_ENABLED; + private boolean sslEnabled = DEFAULT_SSL_ENABLED; + + private int maxSchemaAgreementWaitSeconds = DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS; + private int port = DEFAULT_PORT; + + private AddressTranslator addressTranslator; + + private AuthProvider authProvider; + private Cluster cluster; - /* - * Attributes needed for cluster builder - */ - private String contactPoints = DEFAULT_CONTACT_POINTS; - private int port = CassandraCqlClusterFactoryBean.DEFAULT_PORT; - - // Protocol options private CompressionType compressionType; - private SSLOptions sslOptions; - private boolean sslEnabled = DEFAULT_SSL_ENABLED; - private AuthProvider authProvider; - private String username; - private String password; - private NettyOptions nettyOptions; - private ProtocolVersion protocolVersion; - - // Policies - private LoadBalancingPolicy loadBalancingPolicy; - private ReconnectionPolicy reconnectionPolicy; - private RetryPolicy retryPolicy; - - private PoolingOptions poolingOptions; - private QueryOptions queryOptions; - private SocketOptions socketOptions; - - private boolean metricsEnabled = DEFAULT_METRICS_ENABLED; - private boolean jmxReportingEnabled = DEFAULT_JMX_REPORTING_ENABLED; private Host.StateListener hostStateListener; + private LatencyTracker latencyTracker; - // Startup and shutdown actions - private Set> keyspaceSpecifications = new HashSet>(); private List keyspaceCreations = new ArrayList(); private List keyspaceDrops = new ArrayList(); private List startupScripts = new ArrayList(); private List shutdownScripts = new ArrayList(); + private LoadBalancingPolicy loadBalancingPolicy; + + private NettyOptions nettyOptions; + private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator(); - /* (non-Javadoc) - * @see org.springframework.beans.factory.FactoryBean#getObject() - */ - @Override - public Cluster getObject() { - return cluster; - } + private PoolingOptions poolingOptions; - /* (non-Javadoc) - * @see org.springframework.beans.factory.FactoryBean#getObjectType() - */ - @Override - public Class getObjectType() { - return Cluster.class; - } + private ProtocolVersion protocolVersion; - /* (non-Javadoc) - * @see org.springframework.beans.factory.FactoryBean#isSingleton() - */ - @Override - public boolean isSingleton() { - return true; - } + private QueryOptions queryOptions; - /* (non-Javadoc) - * @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException) - */ - @Override - public DataAccessException translateExceptionIfPossible(RuntimeException ex) { - return exceptionTranslator.translateExceptionIfPossible(ex); - } + private ReconnectionPolicy reconnectionPolicy; - /* (non-Javadoc) + private RetryPolicy retryPolicy; + + private Set> keyspaceSpecifications = new HashSet>(); + + private SpeculativeExecutionPolicy speculativeExecutionPolicy; + + private SocketOptions socketOptions; + + private SSLOptions sslOptions; + + private String beanName; + private String clusterName; + private String contactPoints = DEFAULT_CONTACT_POINTS; + private String password; + private String username; + + private TimestampGenerator timestampGenerator; + + /* + * (non-Javadoc) * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ @Override public void afterPropertiesSet() throws Exception { if (!StringUtils.hasText(contactPoints)) { - throw new IllegalArgumentException("at least one server is required"); + throw new IllegalArgumentException("At least one server is required"); } - Cluster.Builder builder = Cluster.builder(); + Cluster.Builder clusterBuilder = newClusterBuilder(); - builder.addContactPoints(StringUtils.commaDelimitedListToStringArray(contactPoints)).withPort(port); + clusterBuilder.addContactPoints(StringUtils.commaDelimitedListToStringArray(contactPoints)).withPort(port); if (compressionType != null) { - builder.withCompression(convertCompressionType(compressionType)); + clusterBuilder.withCompression(convertCompressionType(compressionType)); } if (poolingOptions != null) { - builder.withPoolingOptions(poolingOptions); + clusterBuilder.withPoolingOptions(poolingOptions); } if (socketOptions != null) { - builder.withSocketOptions(socketOptions); + clusterBuilder.withSocketOptions(socketOptions); } if (queryOptions != null) { - builder.withQueryOptions(queryOptions); + clusterBuilder.withQueryOptions(queryOptions); } if (authProvider != null) { - builder.withAuthProvider(authProvider); + clusterBuilder.withAuthProvider(authProvider); } else if (username != null) { - builder.withCredentials(username, password); + clusterBuilder.withCredentials(username, password); } if (nettyOptions != null) { - builder.withNettyOptions(nettyOptions); + clusterBuilder.withNettyOptions(nettyOptions); } if (loadBalancingPolicy != null) { - builder.withLoadBalancingPolicy(loadBalancingPolicy); + clusterBuilder.withLoadBalancingPolicy(loadBalancingPolicy); } if (reconnectionPolicy != null) { - builder.withReconnectionPolicy(reconnectionPolicy); + clusterBuilder.withReconnectionPolicy(reconnectionPolicy); } if (retryPolicy != null) { - builder.withRetryPolicy(retryPolicy); + clusterBuilder.withRetryPolicy(retryPolicy); } if (!metricsEnabled) { - builder.withoutMetrics(); + clusterBuilder.withoutMetrics(); } if (!jmxReportingEnabled) { - builder.withoutJMXReporting(); + clusterBuilder.withoutJMXReporting(); } if (sslEnabled) { if (sslOptions == null) { - builder.withSSL(); + clusterBuilder.withSSL(); } else { - builder.withSSL(sslOptions); + clusterBuilder.withSSL(sslOptions); } } if (protocolVersion != null) { - builder.withProtocolVersion(protocolVersion); + clusterBuilder.withProtocolVersion(protocolVersion); } - cluster = builder.build(); + if (addressTranslator != null) { + clusterBuilder.withAddressTranslator(addressTranslator); + } + + String clusterName = resolveClusterName(); + + if (StringUtils.hasText(clusterName)) { + clusterBuilder.withClusterName(clusterName); + } + + clusterBuilder.withMaxSchemaAgreementWaitSeconds(maxSchemaAgreementWaitSeconds); + + if (speculativeExecutionPolicy != null) { + clusterBuilder.withSpeculativeExecutionPolicy(speculativeExecutionPolicy); + } + + if (timestampGenerator != null) { + clusterBuilder.withTimestampGenerator(timestampGenerator); + } + + cluster = clusterBuilder.build(); if (hostStateListener != null) { cluster.register(hostStateListener); @@ -241,45 +252,94 @@ public class CassandraCqlClusterFactoryBean executeSpecsAndScripts(keyspaceCreations, startupScripts); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * @see com.datastax.driver.core.Cluster#builder() + */ + Cluster.Builder newClusterBuilder() { + return Cluster.builder(); + } + + String resolveClusterName() { + return (StringUtils.hasText(clusterName) ? clusterName : beanName); + } + + /* + * (non-Javadoc) * @see org.springframework.beans.factory.DisposableBean#destroy() */ @Override public void destroy() throws Exception { - executeSpecsAndScripts(keyspaceDrops, shutdownScripts); cluster.close(); } + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#getObject() + */ + @Override + public Cluster getObject() { + return cluster; + } + + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.FactoryBean#getObjectType() + */ + @Override + public Class getObjectType() { + return (cluster != null ? cluster.getClass() : 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); + } + /** * Examines the contents of all the KeyspaceSpecificationFactoryBeans and generates the proper KeyspaceSpecification * from them. */ private void generateSpecificationsFromFactoryBeans() { - for (KeyspaceActionSpecification spec : keyspaceSpecifications) { + for (KeyspaceActionSpecification keyspaceSpecification : keyspaceSpecifications) { - if (spec instanceof CreateKeyspaceSpecification) { - keyspaceCreations.add((CreateKeyspaceSpecification) spec); + if (keyspaceSpecification instanceof CreateKeyspaceSpecification) { + keyspaceCreations.add((CreateKeyspaceSpecification) keyspaceSpecification); } - if (spec instanceof DropKeyspaceSpecification) { - keyspaceDrops.add((DropKeyspaceSpecification) spec); + + if (keyspaceSpecification instanceof DropKeyspaceSpecification) { + keyspaceDrops.add((DropKeyspaceSpecification) keyspaceSpecification); } } } - protected void executeSpecsAndScripts(List> specifications, List scripts) { + protected void executeSpecsAndScripts(List> kepspaceActionSpecifications, + List scripts) { - if (!CollectionUtils.isEmpty(specifications) || !CollectionUtils.isEmpty(scripts)) { + if (!CollectionUtils.isEmpty(kepspaceActionSpecifications) || !CollectionUtils.isEmpty(scripts)) { Session session = cluster.connect(); try { - CqlTemplate template = new CqlTemplate(session); - for (KeyspaceActionSpecification spec : specifications) { - template.execute(toCql(spec)); + for (KeyspaceActionSpecification keyspaceActionSpecification : kepspaceActionSpecifications) { + template.execute(toCql(keyspaceActionSpecification)); } for (String script : scripts) { @@ -293,18 +353,25 @@ public class CassandraCqlClusterFactoryBean } } - private String toCql(KeyspaceActionSpecification spec) { + private String toCql(KeyspaceActionSpecification keyspaceActionSpecification) { - if(spec instanceof CreateKeyspaceSpecification) { - return new CreateKeyspaceCqlGenerator((CreateKeyspaceSpecification) spec).toCql(); - } + return (keyspaceActionSpecification instanceof CreateKeyspaceSpecification + ? new CreateKeyspaceCqlGenerator((CreateKeyspaceSpecification) keyspaceActionSpecification).toCql() + : new DropKeyspaceCqlGenerator((DropKeyspaceSpecification) keyspaceActionSpecification).toCql()); + } - return new DropKeyspaceCqlGenerator((DropKeyspaceSpecification) spec).toCql(); + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.BeanNameAware#setBeanName(String) + */ + @Override + public void setBeanName(String beanName) { + this.beanName = beanName; } /** - * Set a comma-delimited string of the contact points (hosts) to connect to. Default is {@code localhost}, see - * {@link #DEFAULT_CONTACT_POINTS}. + * Set a comma-delimited string of the contact points (hosts) to connect to. Default is {@code localhost}; + * see {@link #DEFAULT_CONTACT_POINTS}. */ public void setContactPoints(String contactPoints) { this.contactPoints = contactPoints; @@ -364,7 +431,6 @@ public class CassandraCqlClusterFactoryBean /** * Set the {@link NettyOptions} used by a client to customize the driver's underlying Netty layer. * - * @param nettyOptions * @since 1.5 */ public void setNettyOptions(NettyOptions nettyOptions) { @@ -458,13 +524,6 @@ public class CassandraCqlClusterFactoryBean return shutdownScripts; } - /** - * @return Returns the keyspaceSpecifications. - */ - public Set> getKeyspaceSpecifications() { - return keyspaceSpecifications; - } - /** * @param keyspaceSpecifications The keyspaceSpecifications to set. */ @@ -472,6 +531,13 @@ public class CassandraCqlClusterFactoryBean this.keyspaceSpecifications = keyspaceSpecifications; } + /** + * @return Returns the keyspaceSpecifications. + */ + public Set> getKeyspaceSpecifications() { + return keyspaceSpecifications; + } + /** * Set the username to use with {@link com.datastax.driver.core.PlainTextAuthProvider}. * @@ -529,6 +595,62 @@ public class CassandraCqlClusterFactoryBean this.latencyTracker = latencyTracker; } + /** + * Configures the address translator used by the new cluster to translate IP addresses received + * from Cassandra nodes into locally query-able addresses. + * + * @param addressTranslator {@link AddressTranslator} used by the new cluster. + * @see com.datastax.driver.core.Cluster.Builder#withAddressTranslator(AddressTranslator) + * @see com.datastax.driver.core.policies.AddressTranslator + */ + public void setAddressTranslator(AddressTranslator addressTranslator) { + this.addressTranslator = addressTranslator; + } + + /** + * An optional name for the create cluster. + * \ + * @param clusterName optional name for the cluster. + * @see com.datastax.driver.core.Cluster.Builder#withClusterName(String) + */ + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + /** + * Sets the maximum time to wait for schema agreement before returning from a DDL query. The timeout is used + * to wait for all currently up hosts in the cluster to agree on the schema. + * + * @param seconds max schema agreement wait in seconds. + * @see com.datastax.driver.core.Cluster.Builder#withMaxSchemaAgreementWaitSeconds(int) + */ + public void setMaxSchemaAgreementWaitSeconds(int seconds) { + this.maxSchemaAgreementWaitSeconds = seconds; + } + + /** + * Configures the speculative execution policy to use for the new cluster. + * + * @param speculativeExecutionPolicy {@link SpeculativeExecutionPolicy} to use with the new cluster. + * @see com.datastax.driver.core.Cluster.Builder#withSpeculativeExecutionPolicy(SpeculativeExecutionPolicy) + * @see com.datastax.driver.core.policies.SpeculativeExecutionPolicy + */ + public void setSpeculativeExecutionPolicy(SpeculativeExecutionPolicy speculativeExecutionPolicy) { + this.speculativeExecutionPolicy = speculativeExecutionPolicy; + } + + /** + * Configures the generator that will produce the client-side timestamp sent with each query. + * + * @param timestampGenerator {@link TimestampGenerator} used to produce a client-side timestamp + * sent with each query. + * @see com.datastax.driver.core.Cluster.Builder#withTimestampGenerator(TimestampGenerator) + * @see com.datastax.driver.core.TimestampGenerator + */ + public void setTimestampGenerator(TimestampGenerator timestampGenerator) { + this.timestampGenerator = timestampGenerator; + } + private static Compression convertCompressionType(CompressionType type) { switch (type) { case NONE: @@ -537,6 +659,6 @@ public class CassandraCqlClusterFactoryBean return Compression.SNAPPY; } - throw new IllegalArgumentException("unknown compression type " + type); + throw new IllegalArgumentException(String.format("Unknown compression type [%s]", type)); } } diff --git a/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractClusterConfiguration.java b/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractClusterConfiguration.java index a7d895119..f7e665930 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractClusterConfiguration.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractClusterConfiguration.java @@ -31,9 +31,12 @@ import com.datastax.driver.core.PoolingOptions; import com.datastax.driver.core.ProtocolVersion; import com.datastax.driver.core.QueryOptions; import com.datastax.driver.core.SocketOptions; +import com.datastax.driver.core.TimestampGenerator; +import com.datastax.driver.core.policies.AddressTranslator; import com.datastax.driver.core.policies.LoadBalancingPolicy; import com.datastax.driver.core.policies.ReconnectionPolicy; import com.datastax.driver.core.policies.RetryPolicy; +import com.datastax.driver.core.policies.SpeculativeExecutionPolicy; /** * Base class for Spring Cassandra configuration that can handle creating namespaces, execute arbitrary CQL on startup & @@ -51,22 +54,24 @@ public abstract class AbstractClusterConfiguration { CassandraCqlClusterFactoryBean bean = new CassandraCqlClusterFactoryBean(); - bean.setContactPoints(getContactPoints()); - bean.setPort(getPort()); - + bean.setAddressTranslator(getAddressTranslator()); bean.setAuthProvider(getAuthProvider()); + bean.setClusterName(getClusterName()); bean.setCompressionType(getCompressionType()); - bean.setProtocolVersion(getProtocolVersion()); - + bean.setContactPoints(getContactPoints()); bean.setLoadBalancingPolicy(getLoadBalancingPolicy()); - bean.setReconnectionPolicy(getReconnectionPolicy()); - bean.setRetryPolicy(getRetryPolicy()); + bean.setMaxSchemaAgreementWaitSeconds(getMaxSchemaAgreementWaitSeconds()); bean.setMetricsEnabled(getMetricsEnabled()); bean.setNettyOptions(getNettyOptions()); - bean.setPoolingOptions(getPoolingOptions()); + bean.setPort(getPort()); + bean.setProtocolVersion(getProtocolVersion()); bean.setQueryOptions(getQueryOptions()); + bean.setReconnectionPolicy(getReconnectionPolicy()); + bean.setRetryPolicy(getRetryPolicy()); + bean.setSpeculativeExecutionPolicy(getSpeculativeExecutionPolicy()); bean.setSocketOptions(getSocketOptions()); + bean.setTimestampGenerator(getTimestampGenerator()); bean.setKeyspaceCreations(getKeyspaceCreations()); bean.setKeyspaceDrops(getKeyspaceDrops()); @@ -77,23 +82,13 @@ public abstract class AbstractClusterConfiguration { } /** - * Returns the Cassandra port. Defaults to {@code 9042} + * Returns the {@link AddressTranslator}. * - * @return the Cassandra port - * @see CassandraCqlClusterFactoryBean#DEFAULT_PORT + * @return the {@link AddressTranslator}; may be {@literal null}. + * @since 1.5 */ - protected int getPort() { - return CassandraCqlClusterFactoryBean.DEFAULT_PORT; - } - - /** - * Returns the Cassandra contact points. Defaults to {@code localhost} - * - * @return the Cassandra contact points - * @see CassandraCqlClusterFactoryBean#DEFAULT_CONTACT_POINTS - */ - protected String getContactPoints() { - return CassandraCqlClusterFactoryBean.DEFAULT_CONTACT_POINTS; + protected AddressTranslator getAddressTranslator() { + return null; } /** @@ -105,6 +100,16 @@ public abstract class AbstractClusterConfiguration { return null; } + /** + * Returns the cluster name. + * + * @return the cluster name; may be {@literal null}. + * @since 1.5 + */ + protected String getClusterName() { + return null; + } + /** * Returns the {@link CompressionType}. * @@ -115,12 +120,13 @@ public abstract class AbstractClusterConfiguration { } /** - * Returns the {@link ProtocolVersion}. + * Returns the Cassandra contact points. Defaults to {@code localhost} * - * @return the {@link ProtocolVersion}, may be {@literal null}. + * @return the Cassandra contact points + * @see CassandraCqlClusterFactoryBean#DEFAULT_CONTACT_POINTS */ - protected ProtocolVersion getProtocolVersion() { - return null; + protected String getContactPoints() { + return CassandraCqlClusterFactoryBean.DEFAULT_CONTACT_POINTS; } /** @@ -133,21 +139,12 @@ public abstract class AbstractClusterConfiguration { } /** - * Returns the {@link ReconnectionPolicy}. + * Returns the maximum schema agreement wait in seconds. * - * @return the {@link ReconnectionPolicy}, may be {@literal null}. + * @return the maximum schema agreement wait in seconds; default to {@literal 10} seconds. */ - protected ReconnectionPolicy getReconnectionPolicy() { - return null; - } - - /** - * Returns the {@link RetryPolicy}. - * - * @return the {@link RetryPolicy}, may be {@literal null}. - */ - protected RetryPolicy getRetryPolicy() { - return null; + protected int getMaxSchemaAgreementWaitSeconds() { + return CassandraCqlClusterFactoryBean.DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS; } /** @@ -179,6 +176,25 @@ public abstract class AbstractClusterConfiguration { return null; } + /** + * Returns the Cassandra port. Defaults to {@code 9042} + * + * @return the Cassandra port + * @see CassandraCqlClusterFactoryBean#DEFAULT_PORT + */ + protected int getPort() { + return CassandraCqlClusterFactoryBean.DEFAULT_PORT; + } + + /** + * Returns the {@link ProtocolVersion}. + * + * @return the {@link ProtocolVersion}, may be {@literal null}. + */ + protected ProtocolVersion getProtocolVersion() { + return null; + } + /** * Returns the {@link QueryOptions}. * @@ -189,6 +205,34 @@ public abstract class AbstractClusterConfiguration { return null; } + /** + * Returns the {@link ReconnectionPolicy}. + * + * @return the {@link ReconnectionPolicy}, may be {@literal null}. + */ + protected ReconnectionPolicy getReconnectionPolicy() { + return null; + } + + /** + * Returns the {@link RetryPolicy}. + * + * @return the {@link RetryPolicy}, may be {@literal null}. + */ + protected RetryPolicy getRetryPolicy() { + return null; + } + + /** + * Returns the {@link SpeculativeExecutionPolicy}. + * + * @return the {@link SpeculativeExecutionPolicy}; may be {@literal null}. + * @since 1.5 + */ + protected SpeculativeExecutionPolicy getSpeculativeExecutionPolicy() { + return null; + } + /** * Returns the {@link SocketOptions}. * @@ -198,6 +242,16 @@ public abstract class AbstractClusterConfiguration { return null; } + /** + * Returns the {@link TimestampGenerator}. + * + * @return the {@link TimestampGenerator}; may be {@literal null}. + * @since 1.5 + */ + protected TimestampGenerator getTimestampGenerator() { + return null; + } + /** * Returns the list of keyspace creations to be run right after {@link com.datastax.driver.core.Cluster} * initialization. diff --git a/spring-cql/src/main/java/org/springframework/cassandra/config/xml/CassandraCqlClusterParser.java b/spring-cql/src/main/java/org/springframework/cassandra/config/xml/CassandraCqlClusterParser.java index 93e4ff1e7..0dca42647 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/config/xml/CassandraCqlClusterParser.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/config/xml/CassandraCqlClusterParser.java @@ -89,17 +89,22 @@ public class CassandraCqlClusterParser extends AbstractBeanDefinitionParser { */ protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + addOptionalPropertyReference(builder, "addressTranslator", element, "address-translator-ref"); addOptionalPropertyReference(builder, "authProvider", element, "auth-info-provider-ref"); addOptionalPropertyReference(builder, "hostStateListener", element, "host-state-listener-ref"); addOptionalPropertyReference(builder, "latencyTracker", element, "latency-tracker-ref"); addOptionalPropertyReference(builder, "loadBalancingPolicy", element, "load-balancing-policy-ref"); addOptionalPropertyReference(builder, "reconnectionPolicy", element, "reconnection-policy-ref"); addOptionalPropertyReference(builder, "retryPolicy", element, "retry-policy-ref"); + addOptionalPropertyReference(builder, "speculativeExecutionPolicy", element, "speculative-execution-policy-ref"); addOptionalPropertyReference(builder, "sslOptions", element, "ssl-options-ref"); + addOptionalPropertyReference(builder, "timestampGenerator", element, "timestamp-generator-ref"); + addOptionalPropertyValue(builder, "clusterName", element, "cluster-name"); addOptionalPropertyValue(builder, "contactPoints", element, "contact-points"); addOptionalPropertyValue(builder, "compressionType", element, "compression"); addOptionalPropertyValue(builder, "jmxReportingEnabled", element, "jmx-reporting-enabled"); + addOptionalPropertyValue(builder, "maxSchemaAgreementWaitSeconds", element, "max-schema-agreement-wait-seconds"); addOptionalPropertyValue(builder, "metricsEnabled", element, "metrics-enabled"); addOptionalPropertyValue(builder, "password", element, "password"); addOptionalPropertyValue(builder, "port", element, "port"); diff --git a/spring-cql/src/main/resources/org/springframework/cassandra/config/spring-cql-1.0.xsd b/spring-cql/src/main/resources/org/springframework/cassandra/config/spring-cql-1.0.xsd index c51c2f7b9..8ebf228e8 100644 --- a/spring-cql/src/main/resources/org/springframework/cassandra/config/spring-cql-1.0.xsd +++ b/spring-cql/src/main/resources/org/springframework/cassandra/config/spring-cql-1.0.xsd @@ -105,6 +105,23 @@ The name of the Cassandra Cluster definition; default is "cassandra-cluster". ]]> + + + + + + + + + + + + + + + + + + + + + + + + + @@ -289,6 +320,23 @@ RetryPolicy implementation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DATACASS-226 */ public class CassandraCqlClusterFactoryBeanUnitTests { /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -62,7 +71,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -76,7 +85,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -92,7 +101,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -108,7 +117,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -124,7 +133,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -140,7 +149,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -156,7 +165,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -172,8 +181,8 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 - * @see DATACASS-263 + * @see DATACASS-226 + * @see DATACASS-263 * @throws Exception */ @Test @@ -190,8 +199,8 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 - * @see DATACASS-263 + * @see DATACASS-226 + * @see DATACASS-263 * @throws Exception */ @Test @@ -209,7 +218,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -225,7 +234,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -241,7 +250,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -256,7 +265,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -273,7 +282,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -287,7 +296,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { } /** - * @see DATACASS-226 + * @see DATACASS-226 * @throws Exception */ @Test @@ -300,6 +309,119 @@ public class CassandraCqlClusterFactoryBeanUnitTests { assertThat(getConfiguration(bean).getMetricsOptions().isJMXReportingEnabled(), is(false)); } + /** + * @see DATACASS-316 + */ + @Test + public void shouldSetAddressTranslator() throws Exception { + + AddressTranslator mockAddressTranslator = mock(AddressTranslator.class); + CassandraCqlClusterFactoryBean bean = new CassandraCqlClusterFactoryBean(); + + bean.setAddressTranslator(mockAddressTranslator); + bean.afterPropertiesSet(); + + assertThat(getPolicies(bean).getAddressTranslator(), is(equalTo(mockAddressTranslator))); + } + + /** + * @see DATACASS-317 + */ + @Test + public void shouldSetClusterNameWithBeanNameProperty() throws Exception { + + final Cluster.Builder mockClusterBuilder = mock(Cluster.Builder.class); + + when(mockClusterBuilder.addContactPoints(Matchers.anyVararg())).thenReturn(mockClusterBuilder); + + CassandraCqlClusterFactoryBean bean = new CassandraCqlClusterFactoryBean() { + @Override Cluster.Builder newClusterBuilder() { + return mockClusterBuilder; + } + }; + + bean.setBeanName("ABC"); + bean.setClusterName(" "); + bean.afterPropertiesSet(); + + verify(mockClusterBuilder, times(1)).withClusterName(eq("ABC")); + } + + /** + * @see DATACASS-317 + */ + @Test + public void shouldSetClusterNameWithClusterNameProperty() throws Exception { + + final Cluster.Builder mockClusterBuilder = mock(Cluster.Builder.class); + + when(mockClusterBuilder.addContactPoints(Matchers.anyVararg())).thenReturn(mockClusterBuilder); + + CassandraCqlClusterFactoryBean bean = new CassandraCqlClusterFactoryBean() { + @Override Cluster.Builder newClusterBuilder() { + return mockClusterBuilder; + } + }; + + bean.setBeanName("ABC"); + bean.setClusterName("XYZ"); + bean.afterPropertiesSet(); + + verify(mockClusterBuilder, times(1)).withClusterName(eq("XYZ")); + } + + /** + * @see DATACASS-319 + */ + @Test + public void shouldSetMaxSchemaAgreementWaitSeconds() throws Exception { + + CassandraCqlClusterFactoryBean bean = new CassandraCqlClusterFactoryBean(); + + bean.setMaxSchemaAgreementWaitSeconds(20); + bean.afterPropertiesSet(); + + assertThat(getProtocolOptions(bean).getMaxSchemaAgreementWaitSeconds(), is(equalTo(20))); + } + + /** + * @see DATACASS-320 + */ + @Test + public void shouldSetSpeculativeExecutionPolicy() throws Exception { + + SpeculativeExecutionPolicy mockSpeculativeExecutionPolicy = mock(SpeculativeExecutionPolicy.class); + CassandraCqlClusterFactoryBean bean = new CassandraCqlClusterFactoryBean(); + + bean.setSpeculativeExecutionPolicy(mockSpeculativeExecutionPolicy); + bean.afterPropertiesSet(); + + assertThat(getPolicies(bean).getSpeculativeExecutionPolicy(), is(equalTo(mockSpeculativeExecutionPolicy))); + } + + /** + * @see DATACASS-238 + */ + @Test + public void shouldSetTimestampGenerator() throws Exception { + + TimestampGenerator mockTimestampGenerator = mock(TimestampGenerator.class); + CassandraCqlClusterFactoryBean bean = new CassandraCqlClusterFactoryBean(); + + bean.setTimestampGenerator(mockTimestampGenerator); + bean.afterPropertiesSet(); + + assertThat(getPolicies(bean).getTimestampGenerator(), is(equalTo(mockTimestampGenerator))); + } + + private Policies getPolicies(CassandraCqlClusterFactoryBean bean) throws Exception { + return getConfiguration(bean).getPolicies(); + } + + private ProtocolOptions getProtocolOptions(CassandraCqlClusterFactoryBean bean) throws Exception { + return getConfiguration(bean).getProtocolOptions(); + } + private Configuration getConfiguration(CassandraCqlClusterFactoryBean bean) throws Exception { return bean.getObject().getConfiguration(); } diff --git a/spring-cql/src/test/java/org/springframework/cassandra/config/java/AbstractClusterConfigurationUnitTests.java b/spring-cql/src/test/java/org/springframework/cassandra/config/java/AbstractClusterConfigurationUnitTests.java index 894d81ff6..f0a48dd8c 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/config/java/AbstractClusterConfigurationUnitTests.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/config/java/AbstractClusterConfigurationUnitTests.java @@ -34,14 +34,19 @@ import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Configuration; import com.datastax.driver.core.PlainTextAuthProvider; import com.datastax.driver.core.PoolingOptions; +import com.datastax.driver.core.ProtocolOptions; import com.datastax.driver.core.ProtocolOptions.Compression; import com.datastax.driver.core.ProtocolVersion; import com.datastax.driver.core.QueryOptions; import com.datastax.driver.core.SocketOptions; +import com.datastax.driver.core.TimestampGenerator; +import com.datastax.driver.core.policies.AddressTranslator; import com.datastax.driver.core.policies.ExponentialReconnectionPolicy; import com.datastax.driver.core.policies.LoadBalancingPolicy; +import com.datastax.driver.core.policies.Policies; import com.datastax.driver.core.policies.ReconnectionPolicy; import com.datastax.driver.core.policies.RoundRobinPolicy; +import com.datastax.driver.core.policies.SpeculativeExecutionPolicy; /** * Unit tests for {@link AbstractClusterConfiguration}. @@ -53,7 +58,7 @@ import com.datastax.driver.core.policies.RoundRobinPolicy; public class AbstractClusterConfigurationUnitTests { /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -72,7 +77,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -92,7 +97,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -112,7 +117,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -132,7 +137,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -152,7 +157,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -172,7 +177,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -192,7 +197,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -212,7 +217,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -231,7 +236,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -249,7 +254,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -268,7 +273,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -287,7 +292,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -305,7 +310,7 @@ public class AbstractClusterConfigurationUnitTests { } /** - * @see DATACASS-226 + * @see * @throws Exception */ @Test @@ -322,12 +327,100 @@ public class AbstractClusterConfigurationUnitTests { assertThat(clusterConfiguration.cluster().getShutdownScripts(), is(equalTo(scripts))); } + /** + * DATACASS-316 + */ + @Test + public void shouldSetAddressTranslator() throws Exception { + final AddressTranslator mockAddressTranslator = mock(AddressTranslator.class); + + AbstractClusterConfiguration clusterConfiguration = new AbstractClusterConfiguration() { + @Override protected AddressTranslator getAddressTranslator() { + return mockAddressTranslator; + } + }; + + assertThat(getPolicies(getCluster(clusterConfiguration)).getAddressTranslator(), + is(equalTo(mockAddressTranslator))); + } + + /** + * DATACASS-120 + * DATACASS-317 + */ + @Test + public void shouldSetClusterName() throws Exception { + AbstractClusterConfiguration clusterConfiguration = new AbstractClusterConfiguration() { + @Override protected String getClusterName() { + return "testCluster"; + } + }; + + assertThat(getCluster(clusterConfiguration).getClusterName(), is(equalTo("testCluster"))); + } + + /** + * DATACASS-319 + */ + @Test + public void shouldSetMaxSchemaAgreementWaitInSeconds() throws Exception { + AbstractClusterConfiguration clusterConfiguration = new AbstractClusterConfiguration() { + @Override protected int getMaxSchemaAgreementWaitSeconds() { + return 30; + } + }; + + assertThat(getProtocolOptions(getCluster(clusterConfiguration)).getMaxSchemaAgreementWaitSeconds(), + is(equalTo(30))); + } + + /** + * DATACASS-320 + */ + @Test + public void shouldSetSpeculativeExecutionPolicy() throws Exception { + final SpeculativeExecutionPolicy mockSpeculativeExecutionPolicy = mock(SpeculativeExecutionPolicy.class); + + AbstractClusterConfiguration clusterConfiguration = new AbstractClusterConfiguration() { + @Override protected SpeculativeExecutionPolicy getSpeculativeExecutionPolicy() { + return mockSpeculativeExecutionPolicy; + } + }; + + assertThat(getPolicies(getCluster(clusterConfiguration)).getSpeculativeExecutionPolicy(), + is(equalTo(mockSpeculativeExecutionPolicy))); + } + + /** + * DATACASS-238 + */ + @Test + public void shouldSetTimestampGenerator() throws Exception { + final TimestampGenerator mockTimestampGenerator = mock(TimestampGenerator.class); + + AbstractClusterConfiguration clusterConfiguration = new AbstractClusterConfiguration() { + @Override protected TimestampGenerator getTimestampGenerator() { + return mockTimestampGenerator; + } + }; + + assertThat(getPolicies(getCluster(clusterConfiguration)).getTimestampGenerator(), + is(equalTo(mockTimestampGenerator))); + } + + private Policies getPolicies(Cluster cluster) throws Exception { + return getConfiguration(cluster).getPolicies(); + } + + private ProtocolOptions getProtocolOptions(Cluster cluster) throws Exception { + return getConfiguration(cluster).getProtocolOptions(); + } + private Configuration getConfiguration(Cluster cluster) throws Exception { return cluster.getConfiguration(); } private Cluster getCluster(AbstractClusterConfiguration clusterConfiguration) throws Exception { - CassandraCqlClusterFactoryBean cluster = clusterConfiguration.cluster(); cluster.afterPropertiesSet(); return cluster.getObject(); diff --git a/spring-cql/src/test/java/org/springframework/cassandra/config/xml/CassandraCqlClusterParserUnitTests.java b/spring-cql/src/test/java/org/springframework/cassandra/config/xml/CassandraCqlClusterParserUnitTests.java index 777daf1d8..5ddf55429 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/config/xml/CassandraCqlClusterParserUnitTests.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/config/xml/CassandraCqlClusterParserUnitTests.java @@ -15,6 +15,7 @@ */ package org.springframework.cassandra.config.xml; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -85,16 +86,21 @@ public class CassandraCqlClusterParserUnitTests { BeanDefinition mockContainingBeanDefinition = mock(BeanDefinition.class); when(mockContainingBeanDefinition.getScope()).thenReturn("Singleton"); + when(mockElement.getAttribute("address-translator-ref")).thenReturn("testAddressTranslator"); when(mockElement.getAttribute("auth-info-provider-ref")).thenReturn("testAuthInfoProvider"); when(mockElement.getAttribute("host-state-listener-ref")).thenReturn("testHostStateListener"); when(mockElement.getAttribute("latency-tracker-ref")).thenReturn("testLatencyTracker"); when(mockElement.getAttribute("load-balancing-policy-ref")).thenReturn("testLoadBalancingPolicy"); when(mockElement.getAttribute("reconnection-policy-ref")).thenReturn("testReconnectionPolicy"); when(mockElement.getAttribute("retry-policy-ref")).thenReturn("testRetryPolicy"); + when(mockElement.getAttribute("speculative-execution-policy-ref")).thenReturn("testSpeculativeExecutionPolicy"); when(mockElement.getAttribute("ssl-options-ref")).thenReturn("testSslOptions"); + when(mockElement.getAttribute("timestamp-generator-ref")).thenReturn("testTimestampGenerator"); + when(mockElement.getAttribute("cluster-name")).thenReturn("testCluster"); when(mockElement.getAttribute("contact-points")).thenReturn("skullbox"); when(mockElement.getAttribute("compression")).thenReturn("SNAPPY"); when(mockElement.getAttribute("jmx-reporting-enabled")).thenReturn("true"); + when(mockElement.getAttribute("max-schema-agreement-wait-seconds")).thenReturn("30"); when(mockElement.getAttribute("metrics-enabled")).thenReturn("true"); when(mockElement.getAttribute("password")).thenReturn("p@55w0rd"); when(mockElement.getAttribute("port")).thenReturn("12345"); @@ -116,16 +122,21 @@ public class CassandraCqlClusterParserUnitTests { assertThat(beanDefinition.getDestroyMethodName(), is(equalTo("destroy"))); assertThat((Element) beanDefinition.getSource(), is(equalTo(mockElement))); assertThat(beanDefinition.isLazyInit(), is(false)); + assertThat(getPropertyValueAsString(beanDefinition, "addressTranslator"), is(equalTo("testAddressTranslator"))); assertThat(getPropertyValueAsString(beanDefinition, "authProvider"), is(equalTo("testAuthInfoProvider"))); assertThat(getPropertyValueAsString(beanDefinition, "hostStateListener"), is(equalTo("testHostStateListener"))); assertThat(getPropertyValueAsString(beanDefinition, "latencyTracker"), is(equalTo("testLatencyTracker"))); assertThat(getPropertyValueAsString(beanDefinition, "loadBalancingPolicy"), is(equalTo("testLoadBalancingPolicy"))); assertThat(getPropertyValueAsString(beanDefinition, "reconnectionPolicy"), is(equalTo("testReconnectionPolicy"))); assertThat(getPropertyValueAsString(beanDefinition, "retryPolicy"), is(equalTo("testRetryPolicy"))); + assertThat(getPropertyValueAsString(beanDefinition, "speculativeExecutionPolicy"), is(equalTo("testSpeculativeExecutionPolicy"))); assertThat(getPropertyValueAsString(beanDefinition, "sslOptions"), is(equalTo("testSslOptions"))); + assertThat(getPropertyValueAsString(beanDefinition, "timestampGenerator"), is(equalTo("testTimestampGenerator"))); + assertThat(getPropertyValueAsString(beanDefinition, "clusterName"), is(equalTo("testCluster"))); assertThat(getPropertyValueAsString(beanDefinition, "contactPoints"), is(equalTo("skullbox"))); assertThat(getPropertyValueAsString(beanDefinition, "compressionType"), is(equalTo("SNAPPY"))); assertThat(getPropertyValueAsString(beanDefinition, "jmxReportingEnabled"), is(equalTo("true"))); + assertThat(getPropertyValueAsString(beanDefinition, "maxSchemaAgreementWaitSeconds"), is(equalTo("30"))); assertThat(getPropertyValueAsString(beanDefinition, "metricsEnabled"), is(equalTo("true"))); assertThat(getPropertyValueAsString(beanDefinition, "password"), is(equalTo("p@55w0rd"))); assertThat(getPropertyValueAsString(beanDefinition, "port"), is(equalTo("12345"))); @@ -133,16 +144,21 @@ public class CassandraCqlClusterParserUnitTests { assertThat(getPropertyValueAsString(beanDefinition, "username"), is(equalTo("jonDoe"))); verify(mockContainingBeanDefinition).getScope(); + verify(mockElement).getAttribute(eq("address-translator-ref")); verify(mockElement).getAttribute(eq("auth-info-provider-ref")); verify(mockElement).getAttribute(eq("host-state-listener-ref")); verify(mockElement).getAttribute(eq("latency-tracker-ref")); verify(mockElement).getAttribute(eq("load-balancing-policy-ref")); verify(mockElement).getAttribute(eq("reconnection-policy-ref")); verify(mockElement).getAttribute(eq("retry-policy-ref")); + verify(mockElement).getAttribute(eq("speculative-execution-policy-ref")); + verify(mockElement).getAttribute(eq("timestamp-generator-ref")); verify(mockElement).getAttribute(eq("ssl-options-ref")); + verify(mockElement).getAttribute(eq("cluster-name")); verify(mockElement).getAttribute(eq("contact-points")); verify(mockElement).getAttribute(eq("compression")); verify(mockElement).getAttribute(eq("jmx-reporting-enabled")); + verify(mockElement).getAttribute(eq("max-schema-agreement-wait-seconds")); verify(mockElement).getAttribute(eq("metrics-enabled")); verify(mockElement).getAttribute(eq("password")); verify(mockElement).getAttribute(eq("port")); diff --git a/spring-cql/src/test/java/org/springframework/cassandra/support/BeanDefinitionTestUtils.java b/spring-cql/src/test/java/org/springframework/cassandra/support/BeanDefinitionTestUtils.java index d6807dced..f21234d2a 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/support/BeanDefinitionTestUtils.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/support/BeanDefinitionTestUtils.java @@ -23,7 +23,7 @@ import org.springframework.util.Assert; /** * {@code BeanDefinitionTestUtils} is a collection of {@link org.springframework.beans.factory.config.BeanDefinition} * -based utility methods for use in unit and integration testing scenarios. - * + * * @author Mark Paluch */ public abstract class BeanDefinitionTestUtils { @@ -35,7 +35,7 @@ public abstract class BeanDefinitionTestUtils { /** * Retrieve the {@code propertyValue} from a {@link BeanDefinition} by its {@code propertyName}. - * + * * @param beanDefinition must not be {@literal null}. * @param propertyName must not be {@literal null} or empty. * @return the property value, may be {@literal null}. @@ -47,12 +47,13 @@ public abstract class BeanDefinitionTestUtils { Assert.notNull(propertyName, "Property name must not be empty"); PropertyValue propertyValue = beanDefinition.getPropertyValues().getPropertyValue(propertyName); + return (T) (propertyValue != null ? propertyValue.getValue() : null); } /** * Retrieve the {@code propertyValue} as {@literal String} from a {@link BeanDefinition} by its {@code propertyName}. - * + * * @param beanDefinition must not be {@literal null}. * @param propertyName must not be {@literal null} or empty. * @return the property value, may be {@literal null}. @@ -63,8 +64,8 @@ public abstract class BeanDefinitionTestUtils { Assert.notNull(propertyName, "Property name must not be empty"); Object value = getPropertyValue(beanDefinition, propertyName); - return (value instanceof RuntimeBeanReference ? ((RuntimeBeanReference) value).getBeanName() - : (value != null ? String.valueOf(value) : null)); - } + return (value instanceof RuntimeBeanReference ? ((RuntimeBeanReference) value).getBeanName() + : (value != null ? String.valueOf(value) : null)); + } } diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/XmlConfigIntegrationTests.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/XmlConfigIntegrationTests.java index 51b92b8cb..a3d39a1c9 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/XmlConfigIntegrationTests.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/XmlConfigIntegrationTests.java @@ -35,6 +35,9 @@ import com.datastax.driver.core.HostDistance; import com.datastax.driver.core.PoolingOptions; import com.datastax.driver.core.Session; import com.datastax.driver.core.SocketOptions; +import com.datastax.driver.core.TimestampGenerator; +import com.datastax.driver.core.policies.AddressTranslator; +import com.datastax.driver.core.policies.SpeculativeExecutionPolicy; /** * Test XML namespace configuration using the spring-cql-1.0.xsd. @@ -49,21 +52,29 @@ public class XmlConfigIntegrationTests extends AbstractEmbeddedCassandraIntegrat public static final String KEYSPACE = "xmlconfigtest"; - @Rule public KeyspaceRule keyspaceRule = new KeyspaceRule(cassandraEnvironment, KEYSPACE); + @Rule + public KeyspaceRule keyspaceRule = new KeyspaceRule(cassandraEnvironment, KEYSPACE); private ConfigurableApplicationContext applicationContext; + + private AddressTranslator addressTranslator; private Cluster cluster; private Executor executor; private Session session; + private SpeculativeExecutionPolicy speculativeExecutionPolicy; + private TimestampGenerator timestampGenerator; @Before public void setUp() { this.applicationContext = new ClassPathXmlApplicationContext( "XmlConfigIntegrationTests-context.xml", getClass()); + this.addressTranslator = applicationContext.getBean(AddressTranslator.class); this.cluster = applicationContext.getBean(Cluster.class); this.executor = applicationContext.getBean(Executor.class); this.session = applicationContext.getBean(Session.class); + this.speculativeExecutionPolicy = applicationContext.getBean(SpeculativeExecutionPolicy.class); + this.timestampGenerator = applicationContext.getBean(TimestampGenerator.class); } @After @@ -78,6 +89,18 @@ public class XmlConfigIntegrationTests extends AbstractEmbeddedCassandraIntegrat IntegrationTestUtils.assertKeyspaceExists(KEYSPACE, session); } + @Test + public void clusterConfigurationIsCorrect() { + assertThat(cluster.getConfiguration().getPolicies().getAddressTranslator(), is(equalTo(addressTranslator))); + assertThat(cluster.getClusterName(), is(equalTo("skynet"))); + assertThat(cluster.getConfiguration().getProtocolOptions().getMaxSchemaAgreementWaitSeconds(), is(equalTo(30))); + + assertThat(cluster.getConfiguration().getPolicies().getSpeculativeExecutionPolicy(), + is(equalTo(speculativeExecutionPolicy))); + + assertThat(cluster.getConfiguration().getPolicies().getTimestampGenerator(), is(equalTo(timestampGenerator))); + } + /** * @see DATACASS-298 */ diff --git a/spring-cql/src/test/resources/org/springframework/cassandra/test/integration/config/xml/XmlConfigIntegrationTests-context.xml b/spring-cql/src/test/resources/org/springframework/cassandra/test/integration/config/xml/XmlConfigIntegrationTests-context.xml index 35c3fc561..1c136145c 100644 --- a/spring-cql/src/test/resources/org/springframework/cassandra/test/integration/config/xml/XmlConfigIntegrationTests-context.xml +++ b/spring-cql/src/test/resources/org/springframework/cassandra/test/integration/config/xml/XmlConfigIntegrationTests-context.xml @@ -15,12 +15,25 @@ - - + + + + + + + + @@ -38,6 +51,7 @@ send-buffer-size="65536" so-linger="60" tcp-no-delay="true"/> + diff --git a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd index 7ff9ed16c..3ca64bee0 100644 --- a/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd +++ b/spring-data-cassandra/src/main/resources/org/springframework/data/cassandra/config/spring-cassandra-1.0.xsd @@ -114,6 +114,23 @@ The name of the Cassandra Cluster definition; default is "cassandra-cluster". ]]> + + + + + + + + + + + + + + + + + + + + + + + + + @@ -298,6 +329,23 @@ RetryPolicy implementation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +