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 bf4706f34..dbd61fa0e 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 @@ -28,6 +28,7 @@ import org.springframework.cassandra.core.CqlTemplate; 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; @@ -76,9 +77,7 @@ public class CassandraSessionFactoryBean implements FactoryBean, Initia @Override public void afterPropertiesSet() throws Exception { - if (cluster == null) { - throw new IllegalArgumentException("at least one cluster is required"); - } + Assert.notNull(cluster); session = StringUtils.hasText(keyspaceName) ? cluster.connect(keyspaceName) : cluster.connect(); executeScripts(startupScripts); diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/KeyspaceActionSpecificationFactoryBean.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/KeyspaceActionSpecificationFactoryBean.java index 38e1b2ec2..0a3b8cfb3 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/KeyspaceActionSpecificationFactoryBean.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/KeyspaceActionSpecificationFactoryBean.java @@ -50,7 +50,7 @@ public class KeyspaceActionSpecificationFactoryBean implements FactoryBean networkTopologyDataCenters = new LinkedList(); private List networkTopologyReplicationFactors = new LinkedList(); - private String replicationStrategy; + private ReplicationStrategy replicationStrategy; private long replicationFactor; private boolean durableWrites = false; private boolean ifNotExists = false; @@ -97,18 +97,15 @@ public class KeyspaceActionSpecificationFactoryBean implements FactoryBean replicationStrategyMap = new HashMap(); - replicationStrategyMap.put(new DefaultOption("class", String.class, true, false, true), ReplicationStrategy - .valueOf(replicationStrategy).getValue()); + replicationStrategyMap.put(new DefaultOption("class", String.class, true, false, true), + replicationStrategy.getValue()); - /* - * Just set replication factor for SimpleStrategy - */ - if (replicationStrategy.equals(ReplicationStrategy.SIMPLE_STRATEGY.name())) { + if (replicationStrategy == ReplicationStrategy.SIMPLE_STRATEGY) { replicationStrategyMap.put(new DefaultOption("replication_factor", Long.class, true, false, false), replicationFactor); } - if (replicationStrategy.equals(ReplicationStrategy.NETWORK_TOPOLOGY_STRATEGY.name())) { + if (replicationStrategy == ReplicationStrategy.NETWORK_TOPOLOGY_STRATEGY) { int i = 0; for (String datacenter : networkTopologyDataCenters) { replicationStrategyMap.put(new DefaultOption(datacenter, Long.class, true, false, false), @@ -207,14 +204,14 @@ public class KeyspaceActionSpecificationFactoryBean implements FactoryBean newSimpleReplication(long replicationFactor) { - return MapBuilder.map(Option.class, Object.class) - .entry(new DefaultOption("class", String.class, true, false, true), SIMPLE_REPLICATION_STRATEGY) + return MapBuilder + .map(Option.class, Object.class) + .entry(new DefaultOption("class", String.class, true, false, true), + ReplicationStrategy.SIMPLE_STRATEGY.getValue()) .entry(new DefaultOption("replication_factor", Long.class, true, false, false), replicationFactor).build(); } @@ -64,7 +64,8 @@ public class KeyspaceAttributes { 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); + new DefaultOption("class", String.class, true, false, true), + ReplicationStrategy.NETWORK_TOPOLOGY_STRATEGY.getValue()); for (DataCenterReplication dcr : dataCenterReplications) { builder.entry(new DefaultOption(dcr.dataCenter, Long.class, true, false, false), dcr.replicationFactor); @@ -86,16 +87,16 @@ public class KeyspaceAttributes { } } - private String replicationStrategy = DEFAULT_REPLICATION_STRATEGY; + private ReplicationStrategy replicationStrategy = DEFAULT_REPLICATION_STRATEGY; private long replicationFactor = DEFAULT_REPLICATION_FACTOR; private boolean durableWrites = DEFAULT_DURABLE_WRITES; private Map replicasPerNodeByDataCenter = new HashMap(); - public String getReplicationStrategy() { + public ReplicationStrategy getReplicationStrategy() { return replicationStrategy; } - public void setReplicationStrategy(String replicationStrategy) { + public void setReplicationStrategy(ReplicationStrategy replicationStrategy) { this.replicationStrategy = replicationStrategy; } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraClusterParser.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraClusterParser.java index 77bc4eb85..e2bf4b714 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraClusterParser.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraClusterParser.java @@ -15,7 +15,10 @@ */ package org.springframework.cassandra.config.xml; -import static org.springframework.data.config.ParsingUtils.getSourceBeanDefinition; +import static org.springframework.cassandra.config.xml.ParsingUtils.addOptionalPropertyReference; +import static org.springframework.cassandra.config.xml.ParsingUtils.addOptionalPropertyValue; +import static org.springframework.cassandra.config.xml.ParsingUtils.addRequiredPropertyValue; +import static org.springframework.cassandra.config.xml.ParsingUtils.getSourceBeanDefinition; import java.util.ArrayList; import java.util.List; @@ -35,8 +38,6 @@ import org.springframework.cassandra.config.MultiLevelSetFlattenerFactoryBean; import org.springframework.cassandra.config.PoolingOptionsFactoryBean; import org.springframework.cassandra.config.SocketOptionsFactoryBean; import org.springframework.cassandra.core.keyspace.KeyspaceActionSpecification; -import org.springframework.cassandra.core.keyspace.KeyspaceOption.ReplicationStrategy; -import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; @@ -58,7 +59,7 @@ public class CassandraClusterParser extends AbstractBeanDefinitionParser { throws BeanDefinitionStoreException { String id = super.resolveId(element, definition, parserContext); - return StringUtils.hasText(id) ? id : BeanNames.CASSANDRA_CLUSTER; + return StringUtils.hasText(id) ? id : DefaultBeanNames.CLUSTER; } @Override @@ -91,91 +92,29 @@ public class CassandraClusterParser extends AbstractBeanDefinitionParser { */ protected void doParse(Element element, ParserContext context, BeanDefinitionBuilder builder) { - String contactPoints = element.getAttribute("contactPoints"); - if (StringUtils.hasText(contactPoints)) { - builder.addPropertyValue("contactPoints", contactPoints); - } + addOptionalPropertyValue(builder, "contactPoints", element, "contact-points", null); + addOptionalPropertyValue(builder, "port", element, "port", null); + addOptionalPropertyValue(builder, "compressionType", element, "compression", null); + addOptionalPropertyValue(builder, "username", element, "username", null); + addOptionalPropertyValue(builder, "password", element, "password", null); + addOptionalPropertyValue(builder, "deferredInitialization", element, "deferred-initialization", null); + addOptionalPropertyValue(builder, "metricsEnabled", element, "metrics-enabled", null); + addOptionalPropertyValue(builder, "jmxReportingEnabled", element, "jmx-reporting-enabled", null); + addOptionalPropertyValue(builder, "sslEnabled", element, "ssl-enabled", null); - String port = element.getAttribute("port"); - if (StringUtils.hasText(port)) { - builder.addPropertyValue("port", port); - } - - String compression = element.getAttribute("compression"); - if (StringUtils.hasText(compression)) { - builder.addPropertyValue("compressionType", compression); - } - - String username = element.getAttribute("username"); - if (StringUtils.hasText(username)) { - builder.addPropertyValue("username", username); - } - - String password = element.getAttribute("password"); - if (StringUtils.hasText(password)) { - builder.addPropertyValue("password", password); - } - - String deferredInitialization = element.getAttribute("deferredInitialization"); - if (StringUtils.hasText(deferredInitialization)) { - builder.addPropertyValue("deferredInitialization", deferredInitialization); - } - - String metricsEnabled = element.getAttribute("metricsEnabled"); - if (StringUtils.hasText(metricsEnabled)) { - builder.addPropertyValue("metricsEnabled", metricsEnabled); - } - - String jmxReportingEnabled = element.getAttribute("jmxReportingEnabled"); - if (StringUtils.hasText(jmxReportingEnabled)) { - builder.addPropertyValue("jmxReportingEnabled", jmxReportingEnabled); - } - - String sslEnabled = element.getAttribute("sslEnabled"); - if (StringUtils.hasText(sslEnabled)) { - builder.addPropertyValue("sslEnabled", sslEnabled); - } - - String authProvider = element.getAttribute("auth-info-provider-ref"); - if (StringUtils.hasText(authProvider)) { - builder.addPropertyReference("authProvider", authProvider); - } - - String loadBalancingPolicy = element.getAttribute("load-balancing-policy-ref"); - if (StringUtils.hasText(loadBalancingPolicy)) { - builder.addPropertyReference("loadBalancingPolicy", loadBalancingPolicy); - } - - String reconnectionPolicy = element.getAttribute("reconnection-policy-ref"); - if (StringUtils.hasText(reconnectionPolicy)) { - builder.addPropertyReference("reconnectionPolicy", reconnectionPolicy); - } - - String retryPolicy = element.getAttribute("retry-policy-ref"); - if (StringUtils.hasText(retryPolicy)) { - builder.addPropertyReference("retryPolicy", retryPolicy); - } - - String sslOptions = element.getAttribute("ssl-options-ref"); - if (StringUtils.hasText(sslOptions)) { - builder.addPropertyReference("sslOptions", sslOptions); - } - - String hostStateListener = element.getAttribute("host-state-listener-ref"); - if (StringUtils.hasText(hostStateListener)) { - builder.addPropertyReference("hostStateListener", hostStateListener); - } - - String latencyTracker = element.getAttribute("latency-tracker-ref"); - if (StringUtils.hasText(latencyTracker)) { - builder.addPropertyReference("latencyTracker", latencyTracker); - } + addOptionalPropertyReference(builder, "authProvider", element, "auth-info-provider-ref", null); + addOptionalPropertyReference(builder, "loadBalancingPolicy", element, "load-balancing-policy-ref", null); + addOptionalPropertyReference(builder, "reconnectionPolicy", element, "reconnection-policy-ref", null); + addOptionalPropertyReference(builder, "retryPolicy", element, "retry-policy-ref", null); + addOptionalPropertyReference(builder, "sslOptions", element, "ssl-options-ref", null); + addOptionalPropertyReference(builder, "hostStateListener", element, "host-state-listener-ref", null); + addOptionalPropertyReference(builder, "latencyTracker", element, "latency-tracker-ref", null); parseChildElements(element, context, builder); } /** - * Parse the Child Elemement of {@link BeanNames.CASSANDRA_CLUSTER} + * Parse the Child Element of {@link DefaultBeanNames.CLUSTER} * * @param element The Element being parsed * @param context The Parser Context @@ -223,7 +162,7 @@ public class CassandraClusterParser extends AbstractBeanDefinitionParser { } /* - * If the PoolingOptionsBuilder was initilized during parsing, process it now. + * If the PoolingOptionsBuilder was initialized during parsing, process it now. */ if (poolingOptionsBuilder != null) { builder.addPropertyValue("poolingOptions", getSourceBeanDefinition(poolingOptionsBuilder, context, element)); @@ -236,7 +175,7 @@ public class CassandraClusterParser extends AbstractBeanDefinitionParser { } /** - * Create the Single Factory Bean that will flatten all List> + * Create the Single Factory Bean that will flatten all Set> * * @param element The Element being parsed * @param context The Parser Context @@ -262,20 +201,13 @@ public class CassandraClusterParser extends AbstractBeanDefinitionParser { ManagedList networkTopologyDataCenters = new ManagedList(); ManagedList networkTopologyReplicationFactors = new ManagedList(); - String strategyClass = null; - String replicationFactor = null; if (element != null) { - strategyClass = element.getAttribute("class"); - if (!StringUtils.hasText(strategyClass)) { - strategyClass = KeyspaceAttributes.DEFAULT_REPLICATION_STRATEGY; - } - - replicationFactor = element.getAttribute("replication-factor"); - if (!StringUtils.hasText(replicationFactor)) { - replicationFactor = KeyspaceAttributes.DEFAULT_REPLICATION_FACTOR + ""; - } + addOptionalPropertyValue(builder, "replicationStrategy", element, "class", + KeyspaceAttributes.DEFAULT_REPLICATION_STRATEGY.name()); + addOptionalPropertyValue(builder, "replicationFactor", element, "replication-factor", "" + + KeyspaceAttributes.DEFAULT_REPLICATION_FACTOR); /* * DataCenters only apply to NetworkTolopogyStrategy @@ -285,16 +217,10 @@ public class CassandraClusterParser extends AbstractBeanDefinitionParser { networkTopologyDataCenters.add(dataCenter.getAttribute("name")); networkTopologyReplicationFactors.add(dataCenter.getAttribute("replication-factor")); } - } else { - strategyClass = ReplicationStrategy.SIMPLE_STRATEGY.name(); - replicationFactor = KeyspaceAttributes.DEFAULT_REPLICATION_FACTOR + ""; } - builder.addPropertyValue("replicationStrategy", strategyClass); - builder.addPropertyValue("replicationFactor", replicationFactor); builder.addPropertyValue("networkTopologyDataCenters", networkTopologyDataCenters); builder.addPropertyValue("networkTopologyReplicationFactors", networkTopologyReplicationFactors); - } /** @@ -323,16 +249,16 @@ public class CassandraClusterParser extends AbstractBeanDefinitionParser { } if (hostDistance.equals(HostDistance.LOCAL)) { - ParsingUtils.setPropertyValue(builder, element, "min-simultaneous-requests", "localMinSimultaneousRequests"); - ParsingUtils.setPropertyValue(builder, element, "max-simultaneous-requests", "localMaxSimultaneousRequests"); - ParsingUtils.setPropertyValue(builder, element, "core-connections", "localCoreConnections"); - ParsingUtils.setPropertyValue(builder, element, "max-connections", "localMaxConnections"); + addOptionalPropertyValue(builder, "localMinSimultaneousRequests", element, "min-simultaneous-requests", null); + addOptionalPropertyValue(builder, "localMaxSimultaneousRequests", element, "max-simultaneous-requests", null); + addOptionalPropertyValue(builder, "localCoreConnections", element, "core-connections", null); + addOptionalPropertyValue(builder, "localMaxConnections", element, "max-connections", null); } if (hostDistance.equals(HostDistance.REMOTE)) { - ParsingUtils.setPropertyValue(builder, element, "min-simultaneous-requests", "remoteMinSimultaneousRequests"); - ParsingUtils.setPropertyValue(builder, element, "max-simultaneous-requests", "remoteMaxSimultaneousRequests"); - ParsingUtils.setPropertyValue(builder, element, "core-connections", "remoteCoreConnections"); - ParsingUtils.setPropertyValue(builder, element, "max-connections", "remoteMaxConnections"); + addOptionalPropertyValue(builder, "remoteMinSimultaneousRequests", element, "min-simultaneous-requests", null); + addOptionalPropertyValue(builder, "remoteMaxSimultaneousRequests", element, "max-simultaneous-requests", null); + addOptionalPropertyValue(builder, "remoteCoreConnections", element, "core-connections", null); + addOptionalPropertyValue(builder, "remoteMaxConnections", element, "max-connections", null); } return builder; @@ -349,14 +275,14 @@ public class CassandraClusterParser extends AbstractBeanDefinitionParser { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SocketOptionsFactoryBean.class); - ParsingUtils.setPropertyValue(builder, element, "connect-timeout-mls", "connectTimeoutMillis"); - ParsingUtils.setPropertyValue(builder, element, "keep-alive", "keepAlive"); - ParsingUtils.setPropertyValue(builder, element, "read-timeout-mls", "readTimeoutMillis"); - ParsingUtils.setPropertyValue(builder, element, "reuse-address", "reuseAddress"); - ParsingUtils.setPropertyValue(builder, element, "so-linger", "soLinger"); - ParsingUtils.setPropertyValue(builder, element, "tcp-no-delay", "tcpNoDelay"); - ParsingUtils.setPropertyValue(builder, element, "receive-buffer-size", "receiveBufferSize"); - ParsingUtils.setPropertyValue(builder, element, "send-buffer-size", "sendBufferSize"); + addOptionalPropertyValue(builder, "connectTimeoutMillis", element, "connect-timeout-mls", null); + addOptionalPropertyValue(builder, "keepAlive", element, "keep-alive", null); + addOptionalPropertyValue(builder, "readTimeoutMillis", element, "read-timeout-mls", null); + addOptionalPropertyValue(builder, "reuseAddress", element, "reuse-address", null); + addOptionalPropertyValue(builder, "soLinger", element, "so-linger", null); + addOptionalPropertyValue(builder, "tcpNoDelay", element, "tcp-no-delay", null); + addOptionalPropertyValue(builder, "receiveBufferSize", element, "receive-buffer-size", null); + addOptionalPropertyValue(builder, "sendBufferSize", element, "send-buffer-size", null); return getSourceBeanDefinition(builder, context, element); } @@ -370,21 +296,22 @@ public class CassandraClusterParser extends AbstractBeanDefinitionParser { */ private BeanDefinition getKeyspaceSpecificationBeanDefinition(Element element, ParserContext context) { - String action = element.getAttribute("action"); - - Assert.notNull(action, "Keyspace Action must not be null!"); - BeanDefinitionBuilder keyspaceBuilder = BeanDefinitionBuilder .genericBeanDefinition(KeyspaceActionSpecificationFactoryBean.class); - ParsingUtils.setPropertyValue(keyspaceBuilder, element, "name", "name"); - ParsingUtils.setPropertyValue(keyspaceBuilder, element, "action", "action"); - ParsingUtils.setPropertyValue(keyspaceBuilder, element, "durableWrites", "durableWrites"); + // add required replication defaults + addRequiredPropertyValue(keyspaceBuilder, "replicationStrategy", + KeyspaceAttributes.DEFAULT_REPLICATION_STRATEGY.name()); + addRequiredPropertyValue(keyspaceBuilder, "replicationFactor", "" + KeyspaceAttributes.DEFAULT_REPLICATION_FACTOR); + + // now start parsing + addRequiredPropertyValue(keyspaceBuilder, "name", element, "name"); + addRequiredPropertyValue(keyspaceBuilder, "action", element, "action"); + addOptionalPropertyValue(keyspaceBuilder, "durableWrites", element, "durable-writes", "false"); Element replicationElement = DomUtils.getChildElementByTagName(element, "replication"); parseReplication(replicationElement, keyspaceBuilder); return getSourceBeanDefinition(keyspaceBuilder, context, element); } - } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraNamespaceHandler.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraNamespaceHandler.java index 9d743fa39..a6fffaf3e 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraNamespaceHandler.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraNamespaceHandler.java @@ -18,12 +18,11 @@ package org.springframework.cassandra.config.xml; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /** - * Namespace handler for <cassandra> elements. + * Namespace handler for spring-cassandra. * * @author Alex Shvid * @author Matthew T. Adams */ - public class CassandraNamespaceHandler extends NamespaceHandlerSupport { @Override 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 9fe351d96..344308e42 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,8 +15,9 @@ */ package org.springframework.cassandra.config.xml; -import java.util.ArrayList; -import java.util.List; +import static org.springframework.cassandra.config.xml.ParsingUtils.addOptionalPropertyReference; +import static org.springframework.cassandra.config.xml.ParsingUtils.addRequiredPropertyReference; +import static org.springframework.cassandra.config.xml.ParsingUtils.addRequiredPropertyValue; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; @@ -26,8 +27,9 @@ import org.springframework.beans.factory.xml.ParserContext; import org.springframework.cassandra.config.CassandraSessionFactoryBean; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Attr; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; +import org.w3c.dom.NamedNodeMap; /** * Parser for <session> definitions. @@ -35,7 +37,6 @@ import org.w3c.dom.NodeList; * @author David Webb * @author Matthew T. Adams */ - public class CassandraSessionParser extends AbstractSimpleBeanDefinitionParser { @Override @@ -48,53 +49,76 @@ public class CassandraSessionParser extends AbstractSimpleBeanDefinitionParser { throws BeanDefinitionStoreException { String id = super.resolveId(element, definition, parserContext); - return StringUtils.hasText(id) ? id : BeanNames.CASSANDRA_SESSION; + return StringUtils.hasText(id) ? id : DefaultBeanNames.SESSION; + } + + /** + * Parse the given element. This method is intended to be overridden by subclasses so that any elements not known to + * this class can be properly parsed. The default implementation throws {@link IllegalStateException}. + */ + protected void parseUnhandledElement(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + throw new IllegalStateException(String.format("encountered unhandled element [%s]", element.getLocalName())); + } + + /** + * Parse the given session element attribute. This method is intended to be overridden by subclasses so that any + * attributes not known to this class can be properly parsed. The default implementation throws + * {@link IllegalStateException}. + */ + protected void parseUnhandledSessionElementAttribute(Attr attribute, ParserContext parserContext, + BeanDefinitionBuilder builder) { + throw new IllegalStateException(String.format("encountered unhandled session element attribute [%s]", + attribute.getName())); } @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - parseKeyspaceName(element, builder); - parseClusterRef(element, builder); - parseScripts(element, builder, "startup-cql", "startupScripts"); - parseScripts(element, builder, "shutdown-cql", "shutdownScripts"); + setDefaultProperties(builder); + + parseSessionAttributes(element, parserContext, builder); + parseSessionChildElements(element, parserContext, builder); } - protected void parseScripts(Element element, BeanDefinitionBuilder builder, String elementName, String propertyName) { - - List scripts = parseScripts(element, elementName); - builder.addPropertyValue(propertyName, scripts); + protected void setDefaultProperties(BeanDefinitionBuilder builder) { + addRequiredPropertyReference(builder, "cluster", DefaultBeanNames.CLUSTER); } - protected void parseClusterRef(Element element, BeanDefinitionBuilder builder) { + protected void parseSessionAttributes(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - String clusterRef = element.getAttribute("cluster-ref"); - if (!StringUtils.hasText(clusterRef)) { - clusterRef = BeanNames.CASSANDRA_CLUSTER; - } - builder.addPropertyReference("cluster", clusterRef); - } - - protected void parseKeyspaceName(Element element, BeanDefinitionBuilder builder) { - - String keyspaceName = element.getAttribute("keyspace-name"); - if (!StringUtils.hasText(keyspaceName)) { - keyspaceName = null; - } - builder.addPropertyValue("keyspaceName", keyspaceName); - } - - protected List parseScripts(Element element, String elementName) { - - NodeList nodes = element.getElementsByTagName(elementName); - int length = nodes.getLength(); - List scripts = new ArrayList(length); + NamedNodeMap attributes = element.getAttributes(); + int length = attributes.getLength(); for (int i = 0; i < length; i++) { - Element script = (Element) nodes.item(i); - scripts.add(DomUtils.getTextValue(script)); - } - return scripts; + Attr attribute = (Attr) attributes.item(i); + if ("id".equals(attribute.getName())) { + continue; + } + + String name = attribute.getName(); + + if ("keyspace-name".equals(name)) { + addRequiredPropertyValue(builder, "keyspaceName", attribute); + } else if ("cluster-ref".equals(name)) { + addOptionalPropertyReference(builder, "cluster", attribute, DefaultBeanNames.CLUSTER); + } else { + parseUnhandledSessionElementAttribute(attribute, parserContext, builder); + } + } + } + + protected void parseSessionChildElements(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + for (Element child : DomUtils.getChildElements(element)) { + + if ("startup-cql".equals(child.getLocalName())) { + builder.addPropertyValue("startupScripts", DomUtils.getTextValue(child)); + } else if ("shutdown-cql".equals(child.getLocalName())) { + builder.addPropertyValue("shutdownScripts", DomUtils.getTextValue(child)); + } else { + parseUnhandledElement(child, parserContext, builder); + } + } } } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraTemplateParser.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraTemplateParser.java index c796ec9b2..871bd0bbe 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraTemplateParser.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/CassandraTemplateParser.java @@ -15,6 +15,8 @@ */ package org.springframework.cassandra.config.xml; +import static org.springframework.cassandra.config.xml.ParsingUtils.*; + import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -30,7 +32,6 @@ import org.w3c.dom.Element; * @author David Webb * @author Matthew T. Adams */ - public class CassandraTemplateParser extends AbstractSimpleBeanDefinitionParser { @Override @@ -43,16 +44,11 @@ public class CassandraTemplateParser extends AbstractSimpleBeanDefinitionParser throws BeanDefinitionStoreException { String id = super.resolveId(element, definition, parserContext); - return StringUtils.hasText(id) ? id : BeanNames.CASSANDRA_TEMPLATE; + return StringUtils.hasText(id) ? id : DefaultBeanNames.TEMPLATE; } @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - - String sessionRef = element.getAttribute("session-ref"); - if (!StringUtils.hasText(sessionRef)) { - sessionRef = BeanNames.CASSANDRA_SESSION; - } - builder.addPropertyReference("session", sessionRef); + addOptionalPropertyReference(builder, "session", element, "session-ref", DefaultBeanNames.SESSION); } } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/BeanNames.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/DefaultBeanNames.java similarity index 68% rename from spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/BeanNames.java rename to spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/DefaultBeanNames.java index 07f3537dd..c50dc5316 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/BeanNames.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/DefaultBeanNames.java @@ -20,13 +20,9 @@ package org.springframework.cassandra.config.xml; * @author David Webb * @author Matthew T. Adams */ -public final class BeanNames { +public interface DefaultBeanNames { - private BeanNames() { - } - - public static final String CASSANDRA_CLUSTER = "cassandra-cluster"; - public static final String CASSANDRA_KEYSPACE = "cassandra-keyspace"; - public static final String CASSANDRA_SESSION = "cassandra-session"; - public static final String CASSANDRA_TEMPLATE = "cassandra-template"; + public static final String CLUSTER = "cassandra-cluster"; + public static final String SESSION = "cassandra-session"; + public static final String TEMPLATE = "cql-template"; } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/ParsingUtils.java b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/ParsingUtils.java index 826c26e3c..ae33de574 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/ParsingUtils.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/config/xml/ParsingUtils.java @@ -1,33 +1,295 @@ package org.springframework.cassandra.config.xml; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.ParserContext; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import org.w3c.dom.Attr; import org.w3c.dom.Element; public class ParsingUtils { /** - * Configures a property value for the given property name reading the attribute of the given name from the given - * {@link Element} if the attribute is configured. - * - * @param builder must not be {@literal null}. - * @param element must not be {@literal null}. - * @param attrName must not be {@literal null} or empty. - * @param propertyName must not be {@literal null} or empty. + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. */ - public static void setPropertyValue(BeanDefinitionBuilder builder, Element element, String attrName, - String propertyName) { + public static void addOptionalPropertyValue(BeanDefinitionBuilder builder, String propertyName, Element element, + String attrName, String defaultValue) { + + addProperty(builder, propertyName, element.getAttribute(attrName), defaultValue, false, false); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addOptionalPropertyReference(BeanDefinitionBuilder builder, String propertyName, Element element, + String attrName, String defaultValue) { + + addProperty(builder, propertyName, element.getAttribute(attrName), defaultValue, false, true); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addRequiredPropertyValue(BeanDefinitionBuilder builder, String propertyName, Element element, + String attrName) { + + addProperty(builder, propertyName, element.getAttribute(attrName), null, true, false); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addRequiredPropertyReference(BeanDefinitionBuilder builder, String propertyName, Element element, + String attrName) { + + addProperty(builder, propertyName, element.getAttribute(attrName), null, true, true); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addPropertyValue(BeanDefinitionBuilder builder, String propertyName, Element element, + String attrName, String defaultValue, boolean required) { + + addProperty(builder, propertyName, element.getAttribute(attrName), defaultValue, required, false); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addPropertyReference(BeanDefinitionBuilder builder, String propertyName, Element element, + String attrName, String defaultValue, boolean required) { + + addProperty(builder, propertyName, element.getAttribute(attrName), defaultValue, required, true); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addProperty(BeanDefinitionBuilder builder, String propertyName, Element element, String attrName, + String defaultValue, boolean required, boolean reference) { - Assert.notNull(builder, "BeanDefinitionBuilder must not be null!"); Assert.notNull(element, "Element must not be null!"); Assert.hasText(attrName, "Attribute name must not be null!"); + + addProperty(builder, propertyName, element.getAttribute(attrName), defaultValue, required, reference); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addOptionalPropertyValue(BeanDefinitionBuilder builder, String propertyName, Attr attr, + String defaultValue) { + + addProperty(builder, propertyName, attr, defaultValue, false, false); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addOptionalPropertyReference(BeanDefinitionBuilder builder, String propertyName, Attr attr, + String defaultValue) { + + addProperty(builder, propertyName, attr, defaultValue, false, true); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addRequiredPropertyValue(BeanDefinitionBuilder builder, String propertyName, Attr attr) { + + addProperty(builder, propertyName, attr, null, true, false); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addRequiredPropertyReference(BeanDefinitionBuilder builder, String propertyName, Attr attr) { + + addProperty(builder, propertyName, attr, null, true, true); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addPropertyValue(BeanDefinitionBuilder builder, String propertyName, Attr attr, + String defaultValue, boolean required) { + + addProperty(builder, propertyName, attr, defaultValue, required, false); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addPropertyReference(BeanDefinitionBuilder builder, String propertyName, Attr attr, + String defaultValue, boolean required) { + + addProperty(builder, propertyName, attr, defaultValue, required, true); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addProperty(BeanDefinitionBuilder builder, String propertyName, Attr attr, String defaultValue, + boolean required, boolean reference) { + + Assert.notNull(attr, "Attr must not be null!"); + + addProperty(builder, propertyName, attr.getValue(), defaultValue, required, reference); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addRequiredPropertyValue(BeanDefinitionBuilder builder, String propertyName, String value) { + + addProperty(builder, propertyName, value, null, true, false); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addRequiredPropertyReference(BeanDefinitionBuilder builder, String propertyName, String value) { + + addProperty(builder, propertyName, value, null, true, true); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addOptionalPropertyValue(BeanDefinitionBuilder builder, String propertyName, String value, + String defaultValue) { + + addProperty(builder, propertyName, value, defaultValue, false, false); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addOptionalPropertyReference(BeanDefinitionBuilder builder, String propertyName, String value, + String defaultValue) { + + addProperty(builder, propertyName, value, defaultValue, false, true); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addPropertyValue(BeanDefinitionBuilder builder, String propertyName, String value, + String defaultValue, boolean required) { + + addProperty(builder, propertyName, value, defaultValue, required, false); + } + + /** + * Convenience method that ultimately delegates to + * {@link #addProperty(BeanDefinitionBuilder, String, Element, String, String, boolean, boolean)}. + */ + public static void addPropertyReference(BeanDefinitionBuilder builder, String propertyName, String value, + String defaultValue, boolean required) { + + addProperty(builder, propertyName, value, defaultValue, required, true); + } + + /** + * Adds the named property as a value or reference to the given {@link BeanDefinitionBuilder}, with an optional + * default value. + *

+ * Note: If required is false, value is null or empty, and + * defaultValue is null or empty, then no property is added and this method silently returns. + * + * @param builder The {@link BeanDefinitionBuilder}; must not be null. + * @param propertyName The name of the property being added; must not be null or empty. + * @param value The value of the property being added; may be null. + * @param defaultValue The default value of the property being set. + * @param required If true, then the value parameter must not be null or empty. If + * false, the value parameter may be null, in which case the + * defaultValue is used. If required is false, value is + * null or empty, and defaultValue is null or empty, then no property is added and this method + * silently returns. + * @param reference If true, this method will add the property as a reference, else as a value. + * + * @see BeanDefinitionBuilder#addPropertyReference(String, String) + * @see BeanDefinitionBuilder#addPropertyValue(String, Object) + */ + public static void addProperty(BeanDefinitionBuilder builder, String propertyName, String value, String defaultValue, + boolean required, boolean reference) { + + Assert.notNull(builder, "BeanDefinitionBuilder must not be null!"); Assert.hasText(propertyName, "Property name must not be null!"); - String attr = element.getAttribute(attrName); + if (!StringUtils.hasText(value)) { + if (required) { + throw new IllegalStateException(String.format("value required for property %s [%s] on class [%s]", + reference ? "reference" : "", propertyName, builder.getBeanDefinition().getClass().getName())); + } + // else optional; use default + if (defaultValue != null) { + value = defaultValue; + } else { // no default value given; quietly ignore & return + return; + } + } - if (StringUtils.hasText(attr)) { - builder.addPropertyValue(propertyName, attr); + if (reference) { + builder.addPropertyReference(propertyName, value); + } else { + builder.addPropertyValue(propertyName, value); } } + + /** + * Returns the {@link BeanDefinition} built by the given {@link BeanDefinitionBuilder} enriched with source + * information derived from the given {@link Element}. + * + * @param builder must not be {@literal null}. + * @param context must not be {@literal null}. + * @param element must not be {@literal null}. + * @return + */ + public static AbstractBeanDefinition getSourceBeanDefinition(BeanDefinitionBuilder builder, ParserContext context, + Element element) { + + Assert.notNull(element, "Element must not be null!"); + Assert.notNull(context, "ParserContext must not be null!"); + + return getSourceBeanDefinition(builder, context.extractSource(element)); + } + + /** + * Returns the {@link AbstractBeanDefinition} built by the given builder with the given extracted source applied. + * + * @param builder must not be {@literal null}. + * @param source + * @return + */ + public static AbstractBeanDefinition getSourceBeanDefinition(BeanDefinitionBuilder builder, Object source) { + + Assert.notNull(builder, "Builder must not be null!"); + + AbstractBeanDefinition definition = builder.getRawBeanDefinition(); + definition.setSource(source); + return definition; + } } diff --git a/spring-cassandra/src/main/java/org/springframework/cassandra/support/CassandraAccessor.java b/spring-cassandra/src/main/java/org/springframework/cassandra/support/CassandraAccessor.java index b41e852e5..359605c01 100644 --- a/spring-cassandra/src/main/java/org/springframework/cassandra/support/CassandraAccessor.java +++ b/spring-cassandra/src/main/java/org/springframework/cassandra/support/CassandraAccessor.java @@ -18,6 +18,7 @@ package org.springframework.cassandra.support; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; import com.datastax.driver.core.Session; @@ -53,6 +54,7 @@ public class CassandraAccessor implements InitializingBean { /** * Ensure that the Cassandra Session has been set */ + @Override public void afterPropertiesSet() { if (getSession() == null) { throw new IllegalArgumentException("Property 'session' is required"); @@ -70,7 +72,7 @@ public class CassandraAccessor implements InitializingBean { * @param session The session to set. */ public void setSession(Session session) { + Assert.notNull(session); this.session = session; } - } 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 6eed171ab..25de1e5a0 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 @@ -18,7 +18,7 @@ Defines the configuration elements for Spring Cassandra support. @@ -32,12 +32,12 @@ Defines a Cassandra session. - + @@ -59,16 +59,22 @@ Defines a Cassandra cluster. - - + + + + + + - @@ -111,7 +117,7 @@ The name of the Cassandra Cluster definition; default is "cassandra-cluster". ]]> - - - + - + - + - + - + - + - + @@ -278,8 +286,7 @@ Custom Host State Listener for the Cassandra Cluster. - + @@ -296,8 +303,7 @@ Custom Latency Tracker for the Cassandra Cluster. - + @@ -467,7 +473,7 @@ The name of a Cassandra Keyspace. No default; for the system keyspace, use the @@ -537,7 +543,7 @@ Provides the ability to specify replication factors by data center. + default="SIMPLE_STRATEGY"> + contact-points="localhost" port="${build.cassandra.native_transport_port}"> diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataClusterFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataClusterFactoryBean.java new file mode 100644 index 000000000..ffa0ea7f5 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataClusterFactoryBean.java @@ -0,0 +1,12 @@ +package org.springframework.data.cassandra.config; + +import org.springframework.cassandra.config.CassandraClusterFactoryBean; + +/** + * Spring Data Cassandra extension of CassandraClusterFactoryBean. This class exists only in the name of symmetry, based + * on the other CassandraData*FactoryBean classes. + * + * @author Matthew T. Adams + */ +public class CassandraDataClusterFactoryBean extends CassandraClusterFactoryBean { +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataSessionFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataSessionFactoryBean.java index c2d81c5ad..68c3caf4d 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataSessionFactoryBean.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataSessionFactoryBean.java @@ -8,7 +8,10 @@ import org.springframework.data.cassandra.core.CassandraAdminTemplate; import org.springframework.data.cassandra.mapping.CassandraMappingContext; import org.springframework.data.cassandra.mapping.CassandraPersistentEntity; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import com.datastax.driver.core.KeyspaceMetadata; +import com.datastax.driver.core.Metadata; import com.datastax.driver.core.TableMetadata; public class CassandraDataSessionFactoryBean extends CassandraSessionFactoryBean { @@ -17,17 +20,56 @@ public class CassandraDataSessionFactoryBean extends CassandraSessionFactoryBean protected CassandraAdminTemplate admin; protected CassandraConverter converter; protected CassandraMappingContext mappingContext; + protected Mapping mapping; + protected ClassLoader entityClassLoader = getClass().getClassLoader(); @Override public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); + Assert.notNull(converter); + + if (mapping == null) { + mapping = new Mapping(); + } + admin = new CassandraAdminTemplate(session); admin.setCassandraConverter(converter); + processMappingOverrides(); performSchemaAction(); } + protected void processMappingOverrides() throws ClassNotFoundException { + + if (mapping == null) { + return; + } + + for (EntityMapping entityMapping : mapping.getEntityMappings()) { + + if (entityMapping == null) { + continue; + } + + String entityClassName = entityMapping.getEntityClassName(); + Class entityClass = Class.forName(entityClassName, false, entityClassLoader); + + CassandraPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); + + if (entity == null) { + throw new IllegalStateException(String.format("unknown persistent entity class name [%s]", entityClassName)); + } + + String tableName = entityMapping.getTableName(); + if (!StringUtils.hasText(tableName)) { + continue; + } + + entity.setTableName(tableName); + } + } + protected void performSchemaAction() { boolean dropTables = false; @@ -51,7 +93,18 @@ public class CassandraDataSessionFactoryBean extends CassandraSessionFactoryBean protected void createTables(boolean dropTables, boolean dropUnused) { - for (TableMetadata table : session.getCluster().getMetadata().getKeyspace(keyspaceName).getTables()) { + Metadata md = session.getCluster().getMetadata(); + KeyspaceMetadata kmd = md.getKeyspace(keyspaceName); + + if (kmd == null) { // try lower-cased keyspace name + kmd = md.getKeyspace(keyspaceName.toLowerCase()); + } + + if (kmd == null) { + throw new IllegalStateException(String.format("keyspace [%s] does not exist", keyspaceName)); + } + + for (TableMetadata table : kmd.getTables()) { if (dropTables) { if (dropUnused || mappingContext.usesTable(table)) { admin.dropTable(table.getName()); @@ -62,7 +115,7 @@ public class CassandraDataSessionFactoryBean extends CassandraSessionFactoryBean Collection> entities = converter.getMappingContext().getPersistentEntities(); for (CassandraPersistentEntity entity : entities) { - admin.createTable(false, entity.getTableName(), entity.getType(), null /* TODO */); + admin.createTable(false, entity.getTableName(), entity.getType(), null); // TODO: allow spec of table options } } @@ -84,4 +137,22 @@ public class CassandraDataSessionFactoryBean extends CassandraSessionFactoryBean this.converter = converter; this.mappingContext = converter.getCassandraMappingContext(); } + + public Mapping getMapping() { + return mapping; + } + + public void setMapping(Mapping mapping) { + Assert.notNull(mapping); + this.mapping = mapping; + } + + public ClassLoader getEntityClassLoader() { + return entityClassLoader; + } + + public void setEntityClassLoader(ClassLoader entityClassLoader) { + Assert.notNull(entityClassLoader); + this.entityClassLoader = entityClassLoader; + } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataTemplateFactoryBean.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataTemplateFactoryBean.java new file mode 100644 index 000000000..703cbaf4f --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/CassandraDataTemplateFactoryBean.java @@ -0,0 +1,47 @@ +package org.springframework.data.cassandra.config; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.cassandra.convert.CassandraConverter; +import org.springframework.data.cassandra.core.CassandraOperations; +import org.springframework.data.cassandra.core.CassandraTemplate; +import org.springframework.util.Assert; + +import com.datastax.driver.core.Session; + +public class CassandraDataTemplateFactoryBean implements FactoryBean, InitializingBean { + + protected Session session; + protected CassandraConverter converter; + + @Override + public void afterPropertiesSet() throws Exception { + Assert.notNull(session); + Assert.notNull(converter); + } + + @Override + public CassandraOperations getObject() throws Exception { + return new CassandraTemplate(session, converter); + } + + @Override + public Class getObjectType() { + return CassandraOperations.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + public void setSession(Session session) { + Assert.notNull(session); + this.session = session; + } + + public void setConverter(CassandraConverter converter) { + Assert.notNull(converter); + this.converter = converter; + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java new file mode 100644 index 000000000..43e4ded92 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/DefaultDataBeanNames.java @@ -0,0 +1,9 @@ +package org.springframework.data.cassandra.config; + +import org.springframework.cassandra.config.xml.DefaultBeanNames; + +public interface DefaultDataBeanNames extends DefaultBeanNames { + + public static final String DATA_TEMPLATE = "cassandra-template"; + public static final String CONVERTER = "cassandra-converter"; +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/EntityMapping.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/EntityMapping.java new file mode 100644 index 000000000..9431751b9 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/EntityMapping.java @@ -0,0 +1,55 @@ +package org.springframework.data.cassandra.config; + +/** + * Mapping information for an individual entity class. + * + * @author Matthew T. Adams + */ +public class EntityMapping { + + protected String entityClassName; + protected String tableName; + + public EntityMapping(String entityClassName, String tableName) { + setEntityClassName(entityClassName); + setTableName(tableName); + } + + public String getEntityClassName() { + return entityClassName; + } + + public void setEntityClassName(String entityClassName) { + this.entityClassName = entityClassName; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + @Override + public boolean equals(Object that) { + if (that == null) { + return false; + } + if (this == that) { + return true; + } + if (!(that instanceof EntityMapping)) { + return false; + } + + EntityMapping thatMapping = (EntityMapping) that; + + return this.entityClassName.equals(thatMapping.entityClassName) && this.tableName.equals(thatMapping.tableName); + } + + @Override + public int hashCode() { + return entityClassName.hashCode() ^ tableName.hashCode(); + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/KeyspaceAttributes.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/Mapping.java similarity index 59% rename from spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/KeyspaceAttributes.java rename to spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/Mapping.java index d0f3d5ebb..87b9f5254 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/KeyspaceAttributes.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/Mapping.java @@ -15,17 +15,25 @@ */ package org.springframework.data.cassandra.config; -import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; -public class KeyspaceAttributes extends org.springframework.cassandra.config.KeyspaceAttributes { +public class Mapping { - private Collection tables; + private Set entityMappings = new HashSet(); - public Collection getTables() { - return tables; + public Set getEntityMappings() { + return Collections.unmodifiableSet(entityMappings); } - public void setTables(Collection tables) { - this.tables = tables; + public void setEntityMappings(Set mappings) { + + if (mappings == null) { + entityMappings.clear(); + return; + } + + this.entityMappings = new HashSet(mappings); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/TableAttributes.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/TableAttributes.java deleted file mode 100644 index c10e2eefb..000000000 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/TableAttributes.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2011-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.config; - -/** - * Table attributes are used for manipulation around table at the startup (create/update/validate). - * - * @author Alex Shvid - */ -public class TableAttributes { - - private String entity; - private String name; - - public String getEntity() { - return entity; - } - - public void setEntity(String entity) { - this.entity = entity; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String toString() { - return "TableAttributes [entity=" + entity + "]"; - } - -} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataClusterParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataClusterParser.java new file mode 100644 index 000000000..e2d3dc43f --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataClusterParser.java @@ -0,0 +1,11 @@ +package org.springframework.data.cassandra.config.xml; + +import org.springframework.cassandra.config.xml.CassandraClusterParser; + +/** + * Spring Data Cassandra XML namespace parser for the <cluster> element. + * + * @author Matthew T. Adams + */ +public class CassandraDataClusterParser extends CassandraClusterParser { +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraNamespaceHandler.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java similarity index 62% rename from spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraNamespaceHandler.java rename to spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java index 20e6f54fd..db0e2b79f 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraNamespaceHandler.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataNamespaceHandler.java @@ -15,16 +15,21 @@ */ package org.springframework.data.cassandra.config.xml; +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + /** - * Namespace handler for <cassandra>. + * Namespace handler for spring-data-cassandra. * * @author Alex Shvid + * @author Matthew T. Adams */ - -public class CassandraNamespaceHandler extends org.springframework.cassandra.config.xml.CassandraNamespaceHandler { +public class CassandraDataNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { - super.init(); + + registerBeanDefinitionParser("cluster", new CassandraDataClusterParser()); + registerBeanDefinitionParser("session", new CassandraDataSessionParser()); + registerBeanDefinitionParser("template", new CassandraDataTemplateParser()); } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java new file mode 100644 index 000000000..9e0fe53f0 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataSessionParser.java @@ -0,0 +1,100 @@ +package org.springframework.data.cassandra.config.xml; + +import static org.springframework.cassandra.config.xml.ParsingUtils.*; + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.cassandra.config.xml.CassandraSessionParser; +import org.springframework.data.cassandra.config.DefaultDataBeanNames; +import org.springframework.data.cassandra.config.CassandraDataSessionFactoryBean; +import org.springframework.data.cassandra.config.EntityMapping; +import org.springframework.data.cassandra.config.Mapping; +import org.springframework.data.cassandra.config.SchemaAction; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; + +/** + * Spring Data Cassandra XML namespace parser for the <session> element. + * + * @author Matthew T. Adams + */ +public class CassandraDataSessionParser extends CassandraSessionParser { + + @Override + protected Class getBeanClass(Element element) { + return CassandraDataSessionFactoryBean.class; + } + + @Override + protected void parseUnhandledSessionElementAttribute(Attr attribute, ParserContext parserContext, + BeanDefinitionBuilder builder) { + + String name = attribute.getName(); + + if ("cassandra-converter-ref".equals(name)) { + addOptionalPropertyReference(builder, "converter", attribute, DefaultDataBeanNames.CONVERTER); + } else if ("schema-action".equals(name)) { + addOptionalPropertyValue(builder, "schemaAction", attribute, SchemaAction.NONE.name()); + } else { + super.parseUnhandledSessionElementAttribute(attribute, parserContext, builder); + } + } + + @Override + protected void parseUnhandledElement(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + if ("mapping".equals(element.getLocalName())) { + parseMapping(element, parserContext, builder); + } else { + super.parseUnhandledElement(element, parserContext, builder); + } + } + + protected void parseMapping(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + + // TODO: parse attributes here, if there ever are any + + Set mappings = new HashSet(); + + for (Element child : DomUtils.getChildElementsByTagName(element, "entity")) { + + EntityMapping entityMapping = parseEntity(child); + + if (entityMapping != null) { + mappings.add(entityMapping); + } + } + + Mapping mapping = new Mapping(); + mapping.setEntityMappings(mappings); + + builder.addPropertyValue("mapping", mapping); + } + + protected EntityMapping parseEntity(Element entity) { + + String className = entity.getAttribute("class"); + if (!StringUtils.hasText(className)) { + throw new IllegalStateException("class attribute must not be empty"); + } + + Element table = DomUtils.getChildElementByTagName(entity, "table"); + if (table == null) { + return null; + } + + String tableName = table.getAttribute("name"); + if (!StringUtils.hasText(tableName)) { + tableName = null; + } + + // TODO: parse future entity mappings here, like table options + + return new EntityMapping(className, tableName); + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataTemplateParser.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataTemplateParser.java new file mode 100644 index 000000000..13251df72 --- /dev/null +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/config/xml/CassandraDataTemplateParser.java @@ -0,0 +1,47 @@ +package org.springframework.data.cassandra.config.xml; + +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.cassandra.config.xml.CassandraTemplateParser; +import org.springframework.data.cassandra.config.DefaultDataBeanNames; +import org.springframework.data.cassandra.config.CassandraDataTemplateFactoryBean; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; + +/** + * Spring Data Cassandra XML namespace parser for the <template> element. + * + * @author Matthew T. Adams + */ +public class CassandraDataTemplateParser extends CassandraTemplateParser { + + @Override + protected Class getBeanClass(Element element) { + return CassandraDataTemplateFactoryBean.class; + } + + @Override + protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) + throws BeanDefinitionStoreException { + + String id = super.resolveId(element, definition, parserContext); + return StringUtils.hasText(id) ? id : DefaultDataBeanNames.DATA_TEMPLATE; + } + + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + super.doParse(element, parserContext, builder); + + parseConverterAttribute(element, parserContext, builder); + } + + protected void parseConverterAttribute(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + String converterRef = element.getAttribute("cassandra-converter-ref"); + if (!StringUtils.hasText(converterRef)) { + converterRef = DefaultDataBeanNames.CONVERTER; + } + builder.addPropertyReference("converter", converterRef); + } +} diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java index 754b19b58..09dbc902c 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraAdminTemplate.java @@ -30,7 +30,6 @@ public class CassandraAdminTemplate extends CassandraAccessor implements Cassand private static final Logger log = LoggerFactory.getLogger(CassandraAdminTemplate.class); - private Session session; private CassandraConverter converter; private CassandraMappingContext mappingContext; @@ -197,7 +196,7 @@ public class CassandraAdminTemplate extends CassandraAccessor implements Cassand Assert.notNull(callback); try { - return callback.doInSession(session); + return callback.doInSession(getSession()); } catch (RuntimeException x) { throw tryToConvert(x); } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java index 7f0e2c003..7e929ccbc 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraTemplate.java @@ -46,11 +46,12 @@ import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.Select; /** - * The Cassandra Data Template is a convenience API for all Cassandra Operations using POJOs. This is the "Spring Data" - * flavor of the template. For low level Cassandra Operations use the {@link CqlTemplate} + * The Cassandra Data Template is a convenience API for all Cassandra Operations using POJOs. For low level Cassandra + * Operations use the {@link CqlTemplate} * * @author Alex Shvid * @author David Webb + * @author Matthew T. Adams */ public class CassandraTemplate extends CqlTemplate implements CassandraOperations { @@ -107,7 +108,11 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation * * @param session must not be {@literal null}. * @param converter must not be {@literal null}. + * + * @deprecated use {@link #CassandraTemplate(Session, CassandraConverter)} because session should already be connected + * to keyspace */ + @Deprecated public CassandraTemplate(Session session, CassandraConverter converter, String keyspace) { setSession(session); this.keyspace = keyspace; @@ -937,6 +942,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation * @param callback * @return */ + @Override protected T doExecute(SessionCallback callback) { Assert.notNull(callback); diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java index a525fee58..c0965a4cd 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/BasicCassandraPersistentEntity.java @@ -30,6 +30,7 @@ import org.springframework.expression.Expression; import org.springframework.expression.ParserContext; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -42,7 +43,7 @@ import org.springframework.util.StringUtils; public class BasicCassandraPersistentEntity extends BasicPersistentEntity implements CassandraPersistentEntity, ApplicationContextAware { - private String table; + private String tableName; private final SpelExpressionParser spelParser; private final StandardEvaluationContext spelContext; private final Class type; @@ -68,7 +69,7 @@ public class BasicCassandraPersistentEntity extends BasicPersistentEntity extends BasicPersistentEntity extends MutablePersistentEntity @@ -32,12 +32,13 @@ Defines a Cassandra session. - + @@ -68,7 +69,7 @@ Local pooling options. + minOccurs="0" maxOccurs="1"> - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -253,18 +334,6 @@ RetryPolicy implementation. - - - - - - - - - - - @@ -297,7 +366,7 @@ More connections are created up to a configurable maximum number of connections. - + + + + + + - @@ -372,6 +444,7 @@ Arbitrary CQL script to be executed against the session's keyspace during bean d ]]> + @@ -396,14 +469,6 @@ The name of a Cassandra Keyspace. No default; for the system keyspace, use the ]]> - - - - - @@ -412,6 +477,14 @@ The reference to a CassandraConverter; default is "cassandra-converter". ]]> + + + + + @@ -462,32 +535,14 @@ The name of this keyspace. Required. ]]> - + - - - - - - - - - - - - - - - - - - - ---> - \ No newline at end of file + diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/UserRepositoryIntegrationTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/UserRepositoryIntegrationTests.java index a6c28a178..8426a2138 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/UserRepositoryIntegrationTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/repository/UserRepositoryIntegrationTests.java @@ -32,9 +32,13 @@ import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.test.integration.table.User; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.google.common.collect.Lists; @@ -44,8 +48,8 @@ import com.google.common.collect.Lists; * @author Alex Shvid * */ -// @ContextConfiguration -// @RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) public class UserRepositoryIntegrationTests { @Autowired @@ -100,7 +104,7 @@ public class UserRepositoryIntegrationTests { all = dataOperations.insert(Arrays.asList(tom, bob, alice, scott)); } - // @Test + @Test public void findsUserById() throws Exception { User user = repository.findOne(bob.getUsername()); @@ -109,7 +113,7 @@ public class UserRepositoryIntegrationTests { } - // @Test + @Test public void findsAll() throws Exception { List result = Lists.newArrayList(repository.findAll()); assertThat(result.size(), is(all.size())); @@ -117,7 +121,7 @@ public class UserRepositoryIntegrationTests { } - // @Test + @Test public void findsAllWithGivenIds() { Iterable result = repository.findAll(Arrays.asList(bob.getUsername(), tom.getUsername())); @@ -125,7 +129,7 @@ public class UserRepositoryIntegrationTests { assertThat(result, not(hasItems(alice, scott))); } - // @Test + @Test public void deletesUserCorrectly() throws Exception { repository.delete(tom); @@ -136,7 +140,7 @@ public class UserRepositoryIntegrationTests { assertThat(result, not(hasItem(tom))); } - // @Test + @Test public void deletesUserByIdCorrectly() { repository.delete(tom.getUsername().toString()); diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml index 360df39ce..7e575f6ab 100644 --- a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceTests-context.xml @@ -20,7 +20,7 @@ - diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryIntegrationTests-context.xml b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryIntegrationTests-context.xml index 1b0675ade..c8f75cf2e 100644 --- a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryIntegrationTests-context.xml +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/UserRepositoryIntegrationTests-context.xml @@ -2,18 +2,16 @@ + xsi:schemaLocation=" + http://www.springframework.org/schema/data/cassandra http://www.springframework.org/schema/data/cassandra/spring-cassandra-1.0.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + contactPoints="${cassandra.contactPoints}" port="${cassandra.native_transport_port}"> @@ -21,12 +19,14 @@ min-simultaneous-requests="25" max-simultaneous-requests="100" core-connections="1" max-connections="2" /> - - - + + + @@ -34,17 +34,27 @@ class="org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext" /> + class="org.springframework.data.cassandra.convert.MappingCassandraConverter"> - - + + + + + + + + - + diff --git a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/cassandra.properties b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/cassandra.properties index 358cf0041..7c56bbb5b 100644 --- a/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/cassandra.properties +++ b/spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/test/integration/repository/cassandra.properties @@ -1,3 +1,3 @@ cassandra.contactPoints=localhost cassandra.native_transport_port=@build.cassandra.native_transport_port@ -cassandra.keyspace=TestKS123 +cassandra.keyspace=UserRepositoryIntegrationTests