spring-cassandra now supporting xml config

This commit is contained in:
Matthew Adams
2013-12-10 14:17:56 -06:00
parent 7a0d3733a4
commit ffdeaa9fe8
35 changed files with 450 additions and 945 deletions

View File

@@ -18,6 +18,7 @@ package org.springframework.cassandra.config.xml;
/**
* @author Alex Shvid
* @author David Webb
* @author Matthew T. Adams
*/
public final class BeanNames {
@@ -27,5 +28,5 @@ public final class 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";
}

View File

@@ -74,15 +74,14 @@ public class CassandraClusterParser extends AbstractSimpleBeanDefinitionParser {
builder.addPropertyValue("compressionType", CompressionType.valueOf(compression));
}
postProcess(builder, element);
parseChildElements(builder, element);
}
@Override
protected void postProcess(BeanDefinitionBuilder builder, Element element) {
List<Element> subElements = DomUtils.getChildElements(element);
protected void parseChildElements(BeanDefinitionBuilder builder, Element element) {
List<Element> elements = DomUtils.getChildElements(element);
// parse nested elements
for (Element subElement : subElements) {
for (Element subElement : elements) {
String name = subElement.getLocalName();
if ("local-pooling-options".equals(name)) {
@@ -99,11 +98,10 @@ public class CassandraClusterParser extends AbstractSimpleBeanDefinitionParser {
private BeanDefinition parsePoolingOptions(Element element) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PoolingOptionsConfig.class);
// TODO
// ParsingUtils.setPropertyValue(builder, element, "min-simultaneous-requests", "minSimultaneousRequests");
// ParsingUtils.setPropertyValue(builder, element, "max-simultaneous-requests", "maxSimultaneousRequests");
// ParsingUtils.setPropertyValue(builder, element, "core-connections", "coreConnections");
// ParsingUtils.setPropertyValue(builder, element, "max-connections", "maxConnections");
ParsingUtils.setPropertyValue(builder, element, "min-simultaneous-requests", "minSimultaneousRequests");
ParsingUtils.setPropertyValue(builder, element, "max-simultaneous-requests", "maxSimultaneousRequests");
ParsingUtils.setPropertyValue(builder, element, "core-connections", "coreConnections");
ParsingUtils.setPropertyValue(builder, element, "max-connections", "maxConnections");
return builder.getBeanDefinition();
}
@@ -111,14 +109,13 @@ public class CassandraClusterParser extends AbstractSimpleBeanDefinitionParser {
private BeanDefinition parseSocketOptions(Element element) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SocketOptionsConfig.class);
// TODO
// ParsingUtils.setPropertyValue(builder, element, "connect-timeout-mls", "connectTimeoutMls");
// ParsingUtils.setPropertyValue(builder, element, "keep-alive", "keepAlive");
// 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");
ParsingUtils.setPropertyValue(builder, element, "connect-timeout-mls", "connectTimeoutMls");
ParsingUtils.setPropertyValue(builder, element, "keep-alive", "keepAlive");
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");
return builder.getBeanDefinition();
}

View File

@@ -31,9 +31,10 @@ import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Parser for &lt;keyspace;gt; definitions.
* Parser for &lt;keyspace&gt; definitions.
*
* @author Alex Shvid
* @author Matthew T. Adams
*/
public class CassandraKeyspaceParser extends AbstractSimpleBeanDefinitionParser {
@@ -95,11 +96,10 @@ public class CassandraKeyspaceParser extends AbstractSimpleBeanDefinitionParser
private BeanDefinition parseKeyspaceAttributes(Element element) {
BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(KeyspaceAttributes.class);
// TODO
// ParsingUtils.setPropertyValue(defBuilder, element, "auto", "auto");
// ParsingUtils.setPropertyValue(defBuilder, element, "replication-strategy", "replicationStrategy");
// ParsingUtils.setPropertyValue(defBuilder, element, "replication-factor", "replicationFactor");
// ParsingUtils.setPropertyValue(defBuilder, element, "durable-writes", "durableWrites");
ParsingUtils.setPropertyValue(defBuilder, element, "auto", "auto");
ParsingUtils.setPropertyValue(defBuilder, element, "replication-strategy", "replicationStrategy");
ParsingUtils.setPropertyValue(defBuilder, element, "replication-factor", "replicationFactor");
ParsingUtils.setPropertyValue(defBuilder, element, "durable-writes", "durableWrites");
List<Element> subElements = DomUtils.getChildElements(element);
ManagedList<Object> tables = new ManagedList<Object>(subElements.size());
@@ -122,9 +122,8 @@ public class CassandraKeyspaceParser extends AbstractSimpleBeanDefinitionParser
private BeanDefinition parseTable(Element element) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(TableAttributes.class);
// TODO
// ParsingUtils.setPropertyValue(builder, element, "entity", "entity");
// ParsingUtils.setPropertyValue(builder, element, "name", "name");
ParsingUtils.setPropertyValue(builder, element, "entity", "entity");
ParsingUtils.setPropertyValue(builder, element, "name", "name");
return builder.getBeanDefinition();
}

View File

@@ -18,9 +18,10 @@ package org.springframework.cassandra.config.xml;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* Namespace handler for &lt;cassandra;gt;.
* Namespace handler for &lt;cassandra&gt; elements.
*
* @author Alex Shvid
* @author Matthew T. Adams
*/
public class CassandraNamespaceHandler extends NamespaceHandlerSupport {
@@ -28,9 +29,8 @@ public class CassandraNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("cluster", new CassandraClusterParser());
registerBeanDefinitionParser("keyspace", new CassandraKeyspaceParser());
// registerBeanDefinitionParser("keyspace", new CassandraKeyspaceParser());
registerBeanDefinitionParser("session", new CassandraSessionParser());
registerBeanDefinitionParser("template", new CassandraTemplateParser());
}
}

View File

@@ -15,54 +15,41 @@
*/
package org.springframework.cassandra.config.xml;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cassandra.config.KeyspaceAttributes;
import org.springframework.cassandra.support.CassandraExceptionTranslator;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.util.StringUtils;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.KeyspaceMetadata;
import com.datastax.driver.core.Session;
/**
* Convenient factory for configuring a Cassandra Session. Session is a thread safe singleton and created per a
* keyspace. So, it is enough to have one session per application.
* Factory for configuring a Cassandra {@link Session}, which is a thread-safe singleton. As such, it is sufficient to
* have one {@link Session} per application and keyspace.
*
* @author Alex Shvid
* @author Matthew T. Adams
*/
public class CassandraSessionFactoryBean implements FactoryBean<Session>, InitializingBean, DisposableBean,
BeanClassLoaderAware, PersistenceExceptionTranslator {
PersistenceExceptionTranslator {
private static final Logger log = LoggerFactory.getLogger(CassandraSessionFactoryBean.class);
public static final String DEFAULT_REPLICATION_STRATEGY = "SimpleStrategy";
public static final int DEFAULT_REPLICATION_FACTOR = 1;
private ClassLoader beanClassLoader;
private Cluster cluster;
private Session session;
private String keyspace;
private KeyspaceAttributes keyspaceAttributes;
private String keyspaceName;
private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
public Session getObject() {
return session;
}
@@ -101,7 +88,7 @@ public class CassandraSessionFactoryBean implements FactoryBean<Session>, Initia
throw new IllegalArgumentException("at least one cluster is required");
}
this.session = StringUtils.hasText(this.keyspace) ? cluster.connect(keyspace) : cluster.connect();
this.session = StringUtils.hasText(this.keyspaceName) ? cluster.connect(keyspaceName) : cluster.connect();
}
/*
@@ -109,49 +96,14 @@ public class CassandraSessionFactoryBean implements FactoryBean<Session>, Initia
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
this.session.shutdown();
}
public void setKeyspace(String keyspace) {
this.keyspace = keyspace;
public void setKeyspaceName(String keyspaceName) {
this.keyspaceName = keyspaceName;
}
public void setCluster(Cluster cluster) {
this.cluster = cluster;
}
public void setKeyspaceAttributes(KeyspaceAttributes keyspaceAttributes) {
this.keyspaceAttributes = keyspaceAttributes;
}
private static String compareKeyspaceAttributes(KeyspaceAttributes keyspaceAttributes,
KeyspaceMetadata keyspaceMetadata) {
if (keyspaceAttributes.isDurableWrites() != keyspaceMetadata.isDurableWrites()) {
return "durableWrites";
}
Map<String, String> replication = keyspaceMetadata.getReplication();
String replicationFactorStr = replication.get("replication_factor");
if (replicationFactorStr == null) {
return "replication_factor";
}
try {
int replicationFactor = Integer.parseInt(replicationFactorStr);
if (keyspaceAttributes.getReplicationFactor() != replicationFactor) {
return "replication_factor";
}
} catch (NumberFormatException e) {
return "replication_factor";
}
String attributesStrategy = keyspaceAttributes.getReplicationStrategy();
if (attributesStrategy.indexOf('.') == -1) {
attributesStrategy = "org.apache.cassandra.locator." + attributesStrategy;
}
String replicationStrategy = replication.get("class");
if (!attributesStrategy.equals(replicationStrategy)) {
return "replication_class";
}
return null;
}
}

View File

@@ -20,21 +20,21 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.cassandra.core.SessionFactoryBean;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Parser for &lt;session;gt; definitions.
* Parser for &lt;session&gt; definitions.
*
* @author David Webb
* @author Matthew T. Adams
*/
public class CassandraSessionParser extends AbstractSimpleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return SessionFactoryBean.class;
return CassandraSessionFactoryBean.class;
}
/*
@@ -52,18 +52,16 @@ public class CassandraSessionParser extends AbstractSimpleBeanDefinitionParser {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String keyspaceRef = element.getAttribute("cassandra-keyspace-ref");
if (!StringUtils.hasText(keyspaceRef)) {
keyspaceRef = BeanNames.CASSANDRA_KEYSPACE;
String keyspaceName = element.getAttribute("keyspace-name");
if (!StringUtils.hasText(keyspaceName)) {
keyspaceName = null;
}
builder.addPropertyReference("keyspace", keyspaceRef);
builder.addPropertyValue("keyspaceName", keyspaceName);
postProcess(builder, element);
String clusterRef = element.getAttribute("cluster-ref");
if (!StringUtils.hasText(clusterRef)) {
clusterRef = BeanNames.CASSANDRA_CLUSTER;
}
builder.addPropertyReference("cluster", clusterRef);
}
@Override
protected void postProcess(BeanDefinitionBuilder builder, Element element) {
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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.cassandra.config.xml;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cassandra.core.CassandraTemplate;
import com.datastax.driver.core.Session;
/**
* Factory for configuring a {@link CassandraTemplate}.
*
* @author Matthew T. Adams
*/
public class CassandraTemplateFactoryBean implements FactoryBean<CassandraTemplate>, InitializingBean {
private static final Logger log = LoggerFactory.getLogger(CassandraTemplateFactoryBean.class);
private CassandraTemplate template;
private Session session;
public CassandraTemplate getObject() {
return template;
}
public Class<? extends CassandraTemplate> getObjectType() {
return CassandraTemplate.class;
}
public boolean isSingleton() {
return true;
}
public void afterPropertiesSet() throws Exception {
if (session == null) {
throw new IllegalStateException("session is required");
}
this.template = new CassandraTemplate(session);
}
public void setSession(Session session) {
this.session = session;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2011-2012 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.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.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Parser for &lt;template&gt; definitions.
*
* @author David Webb
* @author Matthew T. Adams
*/
public class CassandraTemplateParser extends AbstractSimpleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return CassandraTemplateFactoryBean.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 : BeanNames.CASSANDRA_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);
}
}

View File

@@ -0,0 +1,33 @@
package org.springframework.cassandra.config.xml;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
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.
*/
public static void setPropertyValue(BeanDefinitionBuilder builder, Element element, String attrName,
String propertyName) {
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!");
Assert.hasText(propertyName, "Property name must not be null!");
String attr = element.getAttribute(attrName);
if (StringUtils.hasText(attr)) {
builder.addPropertyValue(propertyName, attr);
}
}
}

View File

@@ -1,87 +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.cassandra.core;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cassandra.core.Keyspace;
import com.datastax.driver.core.Session;
/**
* @author David Webb
*
*/
public class SessionFactoryBean implements FactoryBean<Session>, InitializingBean {
private Keyspace keyspace;
public SessionFactoryBean() {
}
public SessionFactoryBean(Keyspace keyspace) {
setKeyspace(keyspace);
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
if (keyspace == null) {
throw new IllegalStateException("Keyspace required.");
}
}
/**
* @return Returns the keyspace.
*/
public Keyspace getKeyspace() {
return keyspace;
}
/**
* @param keyspace The keyspace to set.
*/
public void setKeyspace(Keyspace keyspace) {
this.keyspace = keyspace;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
@Override
public Session getObject() {
return keyspace.getSession();
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
@Override
public Class<?> getObjectType() {
return Session.class;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
@Override
public boolean isSingleton() {
return true;
}
}

View File

@@ -12,14 +12,14 @@
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the configuration elements for Spring Cassandra support.
]]></xsd:documentation>
]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="session" type="sessionType">
<xsd:annotation>
<xsd:documentation
source="org.springframework.cassandra.core.SessionFactoryBean"><![CDATA[
Defines a Cassandra Session instance used for accessing Cassandra Keyspace'.
source="org.springframework.cassandra.config.xml.SessionFactoryBean"><![CDATA[
Defines a Cassandra Session.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
@@ -29,11 +29,25 @@ Defines a Cassandra Session instance used for accessing Cassandra Keyspace'.
</xsd:annotation>
</xsd:element>
<xsd:element name="template" type="templateType">
<xsd:annotation>
<xsd:documentation
source="org.springframework.cassandra.config.xml.TemplateFactoryBean"><![CDATA[
Defines a Cassandra Templat.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="org.springframework.cassandra.CassandraTemplate" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:element name="cluster" type="clusterType">
<xsd:annotation>
<xsd:documentation
source="org.springframework.data.cassandra.core.CassandraClusterFactoryBean"><![CDATA[
Defines a Cassandra Cluster instance used for accessing Cassandra'.
source="org.springframework.cassandra.config.xml.CassandraClusterFactoryBean"><![CDATA[
Defines a Cassandra Cluster.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
@@ -43,6 +57,20 @@ Defines a Cassandra Cluster instance used for accessing Cassandra'.
</xsd:annotation>
</xsd:element>
<xsd:element name="keyspace" type="keyspaceType">
<xsd:annotation>
<xsd:documentation
source="org.springframework.data.cassandra.core.CassandraKeyspaceFactoryBean"><![CDATA[
Defines a Cassandra Session instance used for accessing Cassandra Keyspace'.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="com.datastax.driver.core.Session" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="clusterType">
<xsd:sequence>
<xsd:element name="local-pooling-options" type="poolingOptionsType"
@@ -62,24 +90,26 @@ Defines a Cassandra Cluster instance used for accessing Cassandra'.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="contactPoints" type="xsd:string">
<xsd:attribute name="contactPoints" type="xsd:string"
use="optional" default="localhost">
<xsd:annotation>
<xsd:documentation><![CDATA[
The comma separated hosts to Cassandra servers. Default is localhost
The comma separated list of Cassandra servers. Default is localhost.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="port" type="xsd:string" use="optional">
<xsd:attribute name="port" type="xsd:string" use="optional"
default="9042">
<xsd:annotation>
<xsd:documentation><![CDATA[
The port to connect to Cassandra server as native CQL client. Default is 9042
The native CQL port to connect to. Default is 9042.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="compression" default="NONE" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The protocol options compression. Default is 'none'.
The protocol compression option. Default is 'none'.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
@@ -174,20 +204,6 @@ RetryPolicy implementation.
</xsd:attribute>
</xsd:complexType>
<xsd:element name="keyspace" type="keyspaceType">
<xsd:annotation>
<xsd:documentation
source="org.springframework.data.cassandra.core.CassandraKeyspaceFactoryBean"><![CDATA[
Defines a Cassandra Session instance used for accessing Cassandra Keyspace'.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="com.datastax.driver.core.Session" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="keyspaceType">
<xsd:sequence>
<xsd:element name="keyspace-attributes" type="keyspaceAttributesType"
@@ -195,35 +211,17 @@ Defines a Cassandra Session instance used for accessing Cassandra Keyspace'.
</xsd:sequence>
<xsd:attribute name="id" type="xsd:ID" use="optional">
<xsd:annotation>
<xsd:documentation>
<xsd:documentation><![CDATA[
The name of the Keyspace definition (by default
"cassandra-keyspace")
</xsd:documentation>
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="name" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The keyspace name of the Cassandra database.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="cassandra-cluster-ref" type="clusterRef"
use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to a Cassandra Cluster instance. Will default to 'cassandra-cluster'.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="cassandra-converter-ref" type="converterRef"
use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to a CassandraConverter instance. Default is null.
]]>
</xsd:documentation>
The name of the Cassandra keyspace.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
@@ -239,12 +237,11 @@ The reference to a CassandraConverter instance. Default is null.
<xsd:union memberTypes="xsd:string" />
</xsd:simpleType>
<xsd:simpleType name="converterRef">
<xsd:simpleType name="sessionRef" final="union">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to
type="org.springframework.data.cassandra.convert.CassandraConverter" />
<tool:assignable-to type="com.datastax.driver.core.Session" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
@@ -335,55 +332,12 @@ Sets the SO_SNDBUF socket option.
</xsd:complexType>
<xsd:complexType name="keyspaceAttributesType">
<xsd:sequence>
<xsd:element name="table" type="tableType" maxOccurs="unbounded"
minOccurs="0"></xsd:element>
</xsd:sequence>
<xsd:attribute name="auto" default="validate">
<xsd:annotation>
<xsd:documentation><![CDATA[
The keyspace manipulation operation on startup. Default value is 'validate'.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="validate">
<xsd:annotation>
<xsd:documentation><![CDATA[
Validate the keyspace, makes no changes.
]]></xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="update">
<xsd:annotation>
<xsd:documentation><![CDATA[
Update the keyspace.
]]></xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="create">
<xsd:annotation>
<xsd:documentation><![CDATA[
Creates the keyspace, destroying previous data.
]]></xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="create-drop">
<xsd:annotation>
<xsd:documentation><![CDATA[
Creates and then drop the keyspace at the end of the session.
]]></xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="replication-stategy" type="xsd:string"
<xsd:attribute name="replication-strategy" type="xsd:string"
use="optional" default="SimpleStrategy">
<xsd:annotation>
<xsd:documentation><![CDATA[
Replication strategy of the Cassandra keyspace. Default value is 'SimpleStrategy'.
]]></xsd:documentation>
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="replication-factor" type="xsd:string"
@@ -391,32 +345,15 @@ Replication strategy of the Cassandra keyspace. Default value is 'SimpleStrategy
<xsd:annotation>
<xsd:documentation><![CDATA[
Replication factor used by the Cassandra keyspace. Default value is '1'.
]]></xsd:documentation>
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="durable-writes" type="xsd:string"
use="optional" default="true">
<xsd:annotation>
<xsd:documentation><![CDATA[
Support durable writes in the Cassandra keyspace. Default value is 'true'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="tableType">
<xsd:attribute name="entity" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Entity class name.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="name" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Table name override.
]]></xsd:documentation>
Whether to support durable writes in the Cassandra keyspace. Default value is 'true'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
@@ -425,29 +362,44 @@ Table name override.
<xsd:attribute name="id" type="xsd:ID" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the Session definition; "cassandra-session" by default.
]]></xsd:documentation>
The name of the Session definition; default is 'cassandra-session'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="cassandra-keyspace-ref" type="keyspaceRef"
<xsd:attribute name="cluster-ref" type="clusterRef"
use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to a Cassandra Cluster; default is 'cassandra-cluster'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="keyspace-name" type="xsd:string"
use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to a Cassandra Keyspace instance. Will default to 'cassandra-keyspace'.
]]>
</xsd:documentation>
The name of a Cassandra Keyspace. No default; for the system keyspace, use the empty string.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="templateType">
<xsd:attribute name="id" type="xsd:ID" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the template; default is 'cassandra-template'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="session-ref" type="sessionRef"
use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to a Cassandra Session; default is 'cassandra-session'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:simpleType name="keyspaceRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="com.datastax.driver.core.Session" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string" />
</xsd:simpleType>
</xsd:schema>

View File

@@ -7,8 +7,6 @@ import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.thrift.transport.TTransportException;
import org.cassandraunit.utils.EmbeddedCassandraServerHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.KeyspaceMetadata;
@@ -20,12 +18,20 @@ public abstract class AbstractEmbeddedCassandraIntegrationTest {
protected final static String CASSANDRA_HOST = "localhost";
protected final static int CASSANDRA_NATIVE_PORT = 9042;
@BeforeClass
public static void beforeClass() throws ConfigurationException, TTransportException, IOException,
public static void startCassandra() throws ConfigurationException, TTransportException, IOException,
InterruptedException {
EmbeddedCassandraServerHelper.startEmbeddedCassandra(CASSANDRA_CONFIG);
}
public AbstractEmbeddedCassandraIntegrationTest() {
try {
startCassandra();
} catch (Exception e) {
throw new RuntimeException(e);
}
connect();
}
/**
* Whether to clear the cluster before the next test.
*/
@@ -47,6 +53,10 @@ public abstract class AbstractEmbeddedCassandraIntegrationTest {
*/
protected Session session;
protected String keyspace() {
return keyspace;
}
/**
* Returns whether we're currently connected to the cluster.
*/
@@ -58,23 +68,22 @@ public abstract class AbstractEmbeddedCassandraIntegrationTest {
return Cluster.builder().addContactPoint(CASSANDRA_HOST).withPort(CASSANDRA_NATIVE_PORT).build();
}
@Before
public void before() {
public void connect() {
if (connect && !connected()) {
cluster = cluster();
if (keyspace == null) {
if (keyspace() == null) {
session = cluster.connect();
} else {
KeyspaceMetadata kmd = cluster.getMetadata().getKeyspace(keyspace);
KeyspaceMetadata kmd = cluster.getMetadata().getKeyspace(keyspace());
if (kmd == null) { // then create keyspace
session = cluster.connect();
session.execute("CREATE KEYSPACE " + keyspace
session.execute("CREATE KEYSPACE " + keyspace()
+ " WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};");
session.execute("USE " + keyspace + ";");
session.execute("USE " + keyspace() + ";");
} else {// else keyspace already exists
session = cluster.connect(keyspace);
session = cluster.connect(keyspace());
}
}
}

View File

@@ -1,32 +0,0 @@
package org.springframework.cassandra.test.integration.config;
import java.io.IOException;
import javax.inject.Inject;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.thrift.transport.TTransportException;
import org.cassandraunit.utils.EmbeddedCassandraServerHelper;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.datastax.driver.core.Session;
@RunWith(SpringJUnit4ClassRunner.class)
public abstract class AbstractIntegrationTest {
@BeforeClass
public static void startCassandra() throws ConfigurationException, TTransportException, IOException {
EmbeddedCassandraServerHelper.startEmbeddedCassandra("spring-cassandra.yaml");
}
@Inject
public Session session;
@Before
public void assertSession() {
IntegrationTestUtils.assertSession(session);
}
}

View File

@@ -11,6 +11,6 @@ public class IntegrationTestUtils {
}
public static void assertKeyspaceExists(String keyspace, Session session) {
assertNotNull(session.getCluster().getMetadata().getKeyspace(KeyspaceCreatingConfig.KEYSPACE));
assertNotNull(session.getCluster().getMetadata().getKeyspace(keyspace));
}
}

View File

@@ -0,0 +1,23 @@
package org.springframework.cassandra.test.integration.config.java;
import javax.inject.Inject;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.cassandra.test.integration.AbstractEmbeddedCassandraIntegrationTest;
import org.springframework.cassandra.test.integration.config.IntegrationTestUtils;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.datastax.driver.core.Session;
@RunWith(SpringJUnit4ClassRunner.class)
public abstract class AbstractIntegrationTest extends AbstractEmbeddedCassandraIntegrationTest {
@Inject
public Session session;
@Before
public void assertSession() {
IntegrationTestUtils.assertSession(session);
}
}

View File

@@ -1,4 +1,4 @@
package org.springframework.cassandra.test.integration.config;
package org.springframework.cassandra.test.integration.config.java;
import org.springframework.cassandra.config.java.AbstractCassandraConfiguration;
import org.springframework.context.annotation.Configuration;

View File

@@ -1,4 +1,4 @@
package org.springframework.cassandra.test.integration.config;
package org.springframework.cassandra.test.integration.config.java;
import org.springframework.cassandra.config.KeyspaceAttributes;
import org.springframework.cassandra.config.PoolingOptionsConfig;

View File

@@ -1,4 +1,4 @@
package org.springframework.cassandra.test.integration.config;
package org.springframework.cassandra.test.integration.config.java;
import org.springframework.context.annotation.Configuration;

View File

@@ -1,4 +1,4 @@
package org.springframework.cassandra.test.integration.config;
package org.springframework.cassandra.test.integration.config.java;
import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;

View File

@@ -1,4 +1,4 @@
package org.springframework.cassandra.test.integration.config;
package org.springframework.cassandra.test.integration.config.java;
import org.springframework.context.annotation.Configuration;

View File

@@ -1,6 +1,7 @@
package org.springframework.cassandra.test.integration.config;
package org.springframework.cassandra.test.integration.config.java;
import org.junit.Test;
import org.springframework.cassandra.test.integration.config.IntegrationTestUtils;
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = KeyspaceCreatingConfig.class)

View File

@@ -0,0 +1,38 @@
package org.springframework.cassandra.test.integration.config.xml;
import static org.junit.Assert.*;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.cassandra.core.CassandraOperations;
import org.springframework.cassandra.test.integration.AbstractEmbeddedCassandraIntegrationTest;
import org.springframework.cassandra.test.integration.config.IntegrationTestUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.datastax.driver.core.Session;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class MinimalXmlConfigTest extends AbstractEmbeddedCassandraIntegrationTest {
protected String keyspace() {
return "minimalxmlconfigtest";
}
@Inject
Session s;
@Inject
CassandraOperations ops;
@Test
public void test() {
IntegrationTestUtils.assertSession(s);
IntegrationTestUtils.assertKeyspaceExists(keyspace(), s);
assertNotNull(ops);
}
}

View File

@@ -0,0 +1,30 @@
package org.springframework.cassandra.test.integration.config.xml;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.cassandra.test.integration.AbstractEmbeddedCassandraIntegrationTest;
import org.springframework.cassandra.test.integration.config.IntegrationTestUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.datastax.driver.core.Session;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class XmlConfigTest extends AbstractEmbeddedCassandraIntegrationTest {
protected String keyspace() {
return "xmlconfigtest";
}
@Inject
Session s;
@Test
public void test() {
IntegrationTestUtils.assertSession(s);
IntegrationTestUtils.assertKeyspaceExists(keyspace(), s);
}
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cassandra="http://www.springframework.org/schema/cassandra"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/cassandra http://www.springframework.org/schema/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">
<cassandra:cluster port="9042" />
<cassandra:session keyspace-name="minimalxmlconfigtest" />
<cassandra:template />
</beans>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cassandra="http://www.springframework.org/schema/cassandra"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/cassandra http://www.springframework.org/schema/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">
<context:property-placeholder
location="classpath:/org/springframework/cassandra/test/integration/config/xml/xmlconfigtest.properties" />
<cassandra:cluster id="cassandra-cluster"
contactPoints="${cassandra.contactPoints}" port="${cassandra.port}">
<cassandra:local-pooling-options
min-simultaneous-requests="25" max-simultaneous-requests="100"
core-connections="2" max-connections="8" />
<cassandra:remote-pooling-options
min-simultaneous-requests="25" max-simultaneous-requests="100"
core-connections="1" max-connections="2" />
<cassandra:socket-options
connect-timeout-mls="5000" keep-alive="true" reuse-address="true"
so-linger="60" tcp-no-delay="true" receive-buffer-size="65536"
send-buffer-size="65536" />
</cassandra:cluster>
<cassandra:session id="cassandra-session"
keyspace-name="${cassandra.keyspace}" />
<bean id="cassandraTemplate" class="org.springframework.cassandra.core.CassandraTemplate">
<constructor-arg ref="cassandra-session" />
</bean>
</beans>

View File

@@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cassandra="http://www.springframework.org/schema/data/cassandra"
xmlns:context="http://www.springframework.org/schema/context"
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">
<context:property-placeholder
location="classpath:/org/springframework/data/cassandra/test/integration/config/cassandra.properties" />
<cassandra:cluster id="cassandra-cluster"
contactPoints="${cassandra.contactPoints}" port="${cassandra.port}"
compression="SNAPPY">
<cassandra:local-pooling-options
min-simultaneous-requests="25" max-simultaneous-requests="100"
core-connections="2" max-connections="8" />
<cassandra:remote-pooling-options
min-simultaneous-requests="25" max-simultaneous-requests="100"
core-connections="1" max-connections="2" />
<cassandra:socket-options
connect-timeout-mls="5000" keep-alive="true" reuse-address="true"
so-linger="60" tcp-no-delay="true" receive-buffer-size="65536"
send-buffer-size="65536" />
</cassandra:cluster>
<bean id="cassandra-mapping"
class=" org.springframework.data.cassandra.mapping.CassandraMappingContext" />
<bean id="cassandra-converter"
class=" org.springframework.data.cassandra.convert.MappingCassandraConverter">
<constructor-arg ref="cassandra-mapping" />
</bean>
<cassandra:keyspace id="cassandra-keyspace" name="${cassandra.keyspace}"
cassandra-cluster-ref="cassandra-cluster" cassandra-converter-ref="cassandra-converter">
<cassandra:keyspace-attributes auto="update"
replication-stategy="SimpleStrategy" replication-factor="1"
durable-writes="true">
<cassandra:table entity="org.springframework.data.cassandra.test.integration.table.Comment" />
<cassandra:table
entity="org.springframework.data.cassandra.test.integration.table.Notification" />
<cassandra:table entity="org.springframework.data.cassandra.test.integration.table.Post" />
<cassandra:table entity="org.springframework.data.cassandra.test.integration.table.Timeline" />
<cassandra:table entity="org.springframework.data.cassandra.test.integration.table.User" />
</cassandra:keyspace-attributes>
</cassandra:keyspace>
<cassandra:session id="cassandra-session" cassandra-keyspace-ref="cassandra-keyspace"/>
<bean id="cassandraTemplate" class="org.springframework.cassandra.core.CassandraTemplate">
<constructor-arg ref="cassandra-session" />
</bean>
</beans>

View File

@@ -1,25 +0,0 @@
/*
* Copyright 2010-2012 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;
/**
* Simple enumeration for the various compression types.
*
* @author Alex Shvid
*/
public enum CompressionType {
NONE, SNAPPY;
}

View File

@@ -1,62 +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;
/**
* Pooling options POJO. Can be remote or local.
*
* @author Alex Shvid
*/
public class PoolingOptionsConfig {
private Integer minSimultaneousRequests;
private Integer maxSimultaneousRequests;
private Integer coreConnections;
private Integer maxConnections;
public Integer getMinSimultaneousRequests() {
return minSimultaneousRequests;
}
public void setMinSimultaneousRequests(Integer minSimultaneousRequests) {
this.minSimultaneousRequests = minSimultaneousRequests;
}
public Integer getMaxSimultaneousRequests() {
return maxSimultaneousRequests;
}
public void setMaxSimultaneousRequests(Integer maxSimultaneousRequests) {
this.maxSimultaneousRequests = maxSimultaneousRequests;
}
public Integer getCoreConnections() {
return coreConnections;
}
public void setCoreConnections(Integer coreConnections) {
this.coreConnections = coreConnections;
}
public Integer getMaxConnections() {
return maxConnections;
}
public void setMaxConnections(Integer maxConnections) {
this.maxConnections = maxConnections;
}
}

View File

@@ -1,89 +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;
/**
* Socket options POJO. Uses to configure Netty.
*
* @author Alex Shvid
*/
public class SocketOptionsConfig {
private Integer connectTimeoutMls;
private Boolean keepAlive;
private Boolean reuseAddress;
private Integer soLinger;
private Boolean tcpNoDelay;
private Integer receiveBufferSize;
private Integer sendBufferSize;
public Integer getConnectTimeoutMls() {
return connectTimeoutMls;
}
public void setConnectTimeoutMls(Integer connectTimeoutMls) {
this.connectTimeoutMls = connectTimeoutMls;
}
public Boolean getKeepAlive() {
return keepAlive;
}
public void setKeepAlive(Boolean keepAlive) {
this.keepAlive = keepAlive;
}
public Boolean getReuseAddress() {
return reuseAddress;
}
public void setReuseAddress(Boolean reuseAddress) {
this.reuseAddress = reuseAddress;
}
public Integer getSoLinger() {
return soLinger;
}
public void setSoLinger(Integer soLinger) {
this.soLinger = soLinger;
}
public Boolean getTcpNoDelay() {
return tcpNoDelay;
}
public void setTcpNoDelay(Boolean tcpNoDelay) {
this.tcpNoDelay = tcpNoDelay;
}
public Integer getReceiveBufferSize() {
return receiveBufferSize;
}
public void setReceiveBufferSize(Integer receiveBufferSize) {
this.receiveBufferSize = receiveBufferSize;
}
public Integer getSendBufferSize() {
return sendBufferSize;
}
public void setSendBufferSize(Integer sendBufferSize) {
this.sendBufferSize = sendBufferSize;
}
}

View File

@@ -1,341 +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.core;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cassandra.support.CassandraExceptionTranslator;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.cassandra.config.KeyspaceAttributes;
import org.springframework.data.cassandra.config.TableAttributes;
import org.springframework.data.cassandra.convert.CassandraConverter;
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.util.CqlUtils;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.KeyspaceMetadata;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.TableMetadata;
import com.datastax.driver.core.exceptions.NoHostAvailableException;
/**
* Convenient factory for configuring a Cassandra Session. Session is a thread safe singleton and created per a
* keyspace. So, it is enough to have one session per application.
*
* @author Alex Shvid
*/
public class CassandraKeyspaceFactoryBean implements FactoryBean<SpringDataKeyspace>, InitializingBean, DisposableBean,
BeanClassLoaderAware, PersistenceExceptionTranslator {
private static final Logger log = LoggerFactory.getLogger(CassandraKeyspaceFactoryBean.class);
public static final String DEFAULT_REPLICATION_STRATEGY = "SimpleStrategy";
public static final int DEFAULT_REPLICATION_FACTOR = 1;
private ClassLoader beanClassLoader;
private Cluster cluster;
private Session session;
private String keyspace;
private CassandraConverter converter;
private MappingContext<? extends CassandraPersistentEntity<?>, CassandraPersistentProperty> mappingContext;
private SpringDataKeyspace keyspaceBean;
private KeyspaceAttributes keyspaceAttributes;
private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
public SpringDataKeyspace getObject() {
return keyspaceBean;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
public Class<? extends Session> getObjectType() {
return Session.class;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
public boolean isSingleton() {
return true;
}
/*
* (non-Javadoc)
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
*/
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
if (this.converter == null) {
this.converter = getDefaultCassandraConverter();
}
this.mappingContext = this.converter.getMappingContext();
if (cluster == null) {
throw new IllegalArgumentException("at least one cluster is required");
}
Session session = null;
session = cluster.connect();
if (StringUtils.hasText(keyspace)) {
KeyspaceMetadata keyspaceMetadata = cluster.getMetadata().getKeyspace(keyspace.toLowerCase());
boolean keyspaceExists = keyspaceMetadata != null;
boolean keyspaceCreated = false;
if (keyspaceExists) {
log.info("keyspace exists " + keyspaceMetadata.asCQLQuery());
}
if (keyspaceAttributes == null) {
keyspaceAttributes = new KeyspaceAttributes();
}
// drop the old keyspace if needed
if (keyspaceExists && (keyspaceAttributes.isCreate() || keyspaceAttributes.isCreateDrop())) {
log.info("Drop keyspace " + keyspace + " on afterPropertiesSet");
session.execute("DROP KEYSPACE " + keyspace + ";");
keyspaceExists = false;
}
// create the new keyspace if needed
if (!keyspaceExists
&& (keyspaceAttributes.isCreate() || keyspaceAttributes.isCreateDrop() || keyspaceAttributes.isUpdate())) {
String query = String
.format(
"CREATE KEYSPACE %1$s WITH replication = { 'class' : '%2$s', 'replication_factor' : %3$d } AND DURABLE_WRITES = %4$b",
keyspace, keyspaceAttributes.getReplicationStrategy(), keyspaceAttributes.getReplicationFactor(),
keyspaceAttributes.isDurableWrites());
log.info("Create keyspace " + keyspace + " on afterPropertiesSet " + query);
session.execute(query);
keyspaceCreated = true;
}
// update keyspace if needed
if (keyspaceAttributes.isUpdate() && !keyspaceCreated) {
if (compareKeyspaceAttributes(keyspaceAttributes, keyspaceMetadata) != null) {
String query = String
.format(
"ALTER KEYSPACE %1$s WITH replication = { 'class' : '%2$s', 'replication_factor' : %3$d } AND DURABLE_WRITES = %4$b",
keyspace, keyspaceAttributes.getReplicationStrategy(), keyspaceAttributes.getReplicationFactor(),
keyspaceAttributes.isDurableWrites());
log.info("Update keyspace " + keyspace + " on afterPropertiesSet " + query);
session.execute(query);
}
}
// validate keyspace if needed
if (keyspaceAttributes.isValidate()) {
if (!keyspaceExists) {
throw new InvalidDataAccessApiUsageException("keyspace '" + keyspace + "' not found in the Cassandra");
}
String errorField = compareKeyspaceAttributes(keyspaceAttributes, keyspaceMetadata);
if (errorField != null) {
throw new InvalidDataAccessApiUsageException(errorField + " attribute is not much in the keyspace '"
+ keyspace + "'");
}
}
session.execute("USE " + keyspace);
if (!CollectionUtils.isEmpty(keyspaceAttributes.getTables())) {
for (TableAttributes tableAttributes : keyspaceAttributes.getTables()) {
String entityClassName = tableAttributes.getEntity();
Class<?> entityClass = ClassUtils.forName(entityClassName, this.beanClassLoader);
CassandraPersistentEntity<?> entity = determineEntity(entityClass);
String useTableName = tableAttributes.getName() != null ? tableAttributes.getName() : entity.getTable();
if (keyspaceCreated) {
createNewTable(session, useTableName, entity);
} else if (keyspaceAttributes.isUpdate()) {
TableMetadata table = keyspaceMetadata.getTable(useTableName.toLowerCase());
if (table == null) {
createNewTable(session, useTableName, entity);
} else {
// alter table columns
for (String cql : CqlUtils.alterTable(useTableName, entity, table)) {
log.info("Execute on keyspace " + keyspace + " CQL " + cql);
session.execute(cql);
}
}
} else if (keyspaceAttributes.isValidate()) {
TableMetadata table = keyspaceMetadata.getTable(useTableName.toLowerCase());
if (table == null) {
throw new InvalidDataAccessApiUsageException("not found table " + useTableName + " for entity "
+ entityClassName);
}
// validate columns
List<String> alter = CqlUtils.alterTable(useTableName, entity, table);
if (!alter.isEmpty()) {
throw new InvalidDataAccessApiUsageException("invalid table " + useTableName + " for entity "
+ entityClassName + ". modify it by " + alter);
}
}
// System.out.println("tableAttributes, entityClass=" + entityClass + ", table = " + entity.getTable());
}
}
}
// initialize property
this.session = session;
this.keyspaceBean = new SpringDataKeyspace(keyspace, session, converter);
}
private void createNewTable(Session session, String useTableName, CassandraPersistentEntity<?> entity)
throws NoHostAvailableException {
String cql = CqlUtils.createTable(useTableName, entity, converter);
log.info("Execute on keyspace " + keyspace + " CQL " + cql);
session.execute(cql);
for (String indexCQL : CqlUtils.createIndexes(useTableName, entity)) {
log.info("Execute on keyspace " + keyspace + " CQL " + indexCQL);
session.execute(indexCQL);
}
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
if (StringUtils.hasText(keyspace) && keyspaceAttributes != null && keyspaceAttributes.isCreateDrop()) {
log.info("Drop keyspace " + keyspace + " on destroy");
session.execute("USE system");
session.execute("DROP KEYSPACE " + keyspace);
}
this.session.shutdown();
}
public void setKeyspace(String keyspace) {
this.keyspace = keyspace;
}
public void setCluster(Cluster cluster) {
this.cluster = cluster;
}
public void setKeyspaceAttributes(KeyspaceAttributes keyspaceAttributes) {
this.keyspaceAttributes = keyspaceAttributes;
}
public void setConverter(CassandraConverter converter) {
this.converter = converter;
}
private static String compareKeyspaceAttributes(KeyspaceAttributes keyspaceAttributes,
KeyspaceMetadata keyspaceMetadata) {
if (keyspaceAttributes.isDurableWrites() != keyspaceMetadata.isDurableWrites()) {
return "durableWrites";
}
Map<String, String> replication = keyspaceMetadata.getReplication();
String replicationFactorStr = replication.get("replication_factor");
if (replicationFactorStr == null) {
return "replication_factor";
}
try {
int replicationFactor = Integer.parseInt(replicationFactorStr);
if (keyspaceAttributes.getReplicationFactor() != replicationFactor) {
return "replication_factor";
}
} catch (NumberFormatException e) {
return "replication_factor";
}
String attributesStrategy = keyspaceAttributes.getReplicationStrategy();
if (attributesStrategy.indexOf('.') == -1) {
attributesStrategy = "org.apache.cassandra.locator." + attributesStrategy;
}
String replicationStrategy = replication.get("class");
if (!attributesStrategy.equals(replicationStrategy)) {
return "replication_class";
}
return null;
}
CassandraPersistentEntity<?> determineEntity(Class<?> entityClass) {
if (entityClass == null) {
throw new InvalidDataAccessApiUsageException(
"No class parameter provided, entity table name can't be determined!");
}
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
if (entity == null) {
throw new InvalidDataAccessApiUsageException("No Persitent Entity information found for the class "
+ entityClass.getName());
}
return entity;
}
private static final CassandraConverter getDefaultCassandraConverter() {
MappingCassandraConverter converter = new MappingCassandraConverter(new CassandraMappingContext());
converter.afterPropertiesSet();
return converter;
}
}