Merge branch 'DATACASS-91'

This commit is contained in:
Matthew Adams
2014-02-12 18:35:17 -06:00
42 changed files with 1234 additions and 362 deletions

View File

@@ -22,7 +22,7 @@ import static org.springframework.cassandra.config.xml.ParsingUtils.addRequiredP
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.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.cassandra.config.CassandraSessionFactoryBean;
import org.springframework.util.StringUtils;
@@ -37,7 +37,7 @@ import org.w3c.dom.NamedNodeMap;
* @author David Webb
* @author Matthew T. Adams
*/
public class CassandraSessionParser extends AbstractSimpleBeanDefinitionParser {
public class CassandraSessionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {

View File

@@ -15,12 +15,12 @@
*/
package org.springframework.cassandra.config.xml;
import static org.springframework.cassandra.config.xml.ParsingUtils.*;
import static org.springframework.cassandra.config.xml.ParsingUtils.addOptionalPropertyReference;
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.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.cassandra.config.CassandraTemplateFactoryBean;
import org.springframework.util.StringUtils;
@@ -32,7 +32,7 @@ import org.w3c.dom.Element;
* @author David Webb
* @author Matthew T. Adams
*/
public class CassandraTemplateParser extends AbstractSimpleBeanDefinitionParser {
public class CassandraTemplateParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {

View File

@@ -22,7 +22,7 @@ package org.springframework.cassandra.config.xml;
*/
public interface DefaultBeanNames {
public static final String CLUSTER = "cassandra-cluster";
public static final String SESSION = "cassandra-session";
public static final String TEMPLATE = "cql-template";
public static final String CLUSTER = "cassandraCluster";
public static final String SESSION = "cassandraSession";
public static final String TEMPLATE = "cqlTemplate";
}

View File

@@ -10,69 +10,66 @@
location="classpath:/org/springframework/cassandra/test/integration/config/xml/ppncxct.properties" />
<bean id="authProvider" class="com.datastax.driver.core.sasl.DseAuthProvider" />
<bean id="loadBalancingPolicy" class="com.datastax.driver.core.policies.DCAwareRoundRobinPolicy">
<bean id="loadBalancingPolicy"
class="com.datastax.driver.core.policies.DCAwareRoundRobinPolicy">
<constructor-arg name="localDc" value="${lb.policy.dcAware.localDc}" />
<constructor-arg name="usedHostsPerRemoteDc" value="${lb.policy.dcAware.remoteHosts}" />
<constructor-arg name="usedHostsPerRemoteDc"
value="${lb.policy.dcAware.remoteHosts}" />
</bean>
<bean id="reconnectionPolicy" class="com.datastax.driver.core.policies.ConstantReconnectionPolicy">
<constructor-arg name="constantDelayMs" value="${cluster.reconnection.delayMillis}"/>
<bean id="reconnectionPolicy"
class="com.datastax.driver.core.policies.ConstantReconnectionPolicy">
<constructor-arg name="constantDelayMs"
value="${cluster.reconnection.delayMillis}" />
</bean>
<bean id="retryPolicy" class="com.datastax.driver.core.policies.DowngradingConsistencyRetryPolicy" />
<bean id="hostStateListener" class="org.springframework.cassandra.test.integration.config.xml.TestHostStateListener"/>
<bean id="latencyTracker" class="org.springframework.cassandra.test.integration.config.xml.TestLatencyTracker"/>
<bean id="retryPolicy"
class="com.datastax.driver.core.policies.DowngradingConsistencyRetryPolicy" />
<cassandra:cluster id="cassandra-cluster"
contact-points="${cluster.contactPoints}" port="${cluster.port}"
compression="${cluster.compression}" auth-info-provider-ref="authProvider"
load-balancing-policy-ref="loadBalancingPolicy" username="${auth.username}" password="${auth.password}"
<bean id="hostStateListener"
class="org.springframework.cassandra.test.integration.config.xml.TestHostStateListener" />
<bean id="latencyTracker"
class="org.springframework.cassandra.test.integration.config.xml.TestLatencyTracker" />
<cassandra:cluster contact-points="${cluster.contactPoints}"
port="${cluster.port}" compression="${cluster.compression}"
auth-info-provider-ref="authProvider" load-balancing-policy-ref="loadBalancingPolicy"
username="${auth.username}" password="${auth.password}"
deferred-initialization="${cluster.deferredInit}" metrics-enabled="${cluster.metricsEnabled}"
jmx-reporting-enabled="${cluster.jmxReportingEnabled}"
reconnection-policy-ref="reconnectionPolicy"
retry-policy-ref="retryPolicy"
host-state-listener-ref="hostStateListener"
latency-tracker-ref="latencyTracker">
<cassandra:local-pooling-options
reconnection-policy-ref="reconnectionPolicy" retry-policy-ref="retryPolicy"
host-state-listener-ref="hostStateListener" latency-tracker-ref="latencyTracker">
<cassandra:local-pooling-options
min-simultaneous-requests="${local.min.requests}"
max-simultaneous-requests="${local.max.requests}"
core-connections="${local.core.connections}"
max-connections="${local.max.connections}"
/>
<cassandra:remote-pooling-options
max-simultaneous-requests="${local.max.requests}" core-connections="${local.core.connections}"
max-connections="${local.max.connections}" />
<cassandra:remote-pooling-options
min-simultaneous-requests="${remote.min.requests}"
max-simultaneous-requests="${remote.max.requests}"
core-connections="${remote.core.connections}"
max-connections="${remote.max.connections}"
/>
<cassandra:socket-options
connect-timeout-millis="${socket.connectTimeoutMillis}"
keep-alive="${socket.keepAlive}"
read-timeout-millis="${socket.readTimeoutMillis}"
reuse-address="${socket.reuseAddress}"
so-linger="${socket.soLinger}"
tcp-no-delay="${socket.tcpNoDelay}"
receive-buffer-size="${socket.receiveBufferSize}"
send-buffer-size="${socket.sendBufferSize}"
/>
<cassandra:keyspace name="${keyspace.name}" action="${keyspace.action}"/>
<cassandra:keyspace name="Foo123" action="CREATE_DROP" durable-writes="true">
max-simultaneous-requests="${remote.max.requests}" core-connections="${remote.core.connections}"
max-connections="${remote.max.connections}" />
<cassandra:socket-options
connect-timeout-millis="${socket.connectTimeoutMillis}" keep-alive="${socket.keepAlive}"
read-timeout-millis="${socket.readTimeoutMillis}" reuse-address="${socket.reuseAddress}"
so-linger="${socket.soLinger}" tcp-no-delay="${socket.tcpNoDelay}"
receive-buffer-size="${socket.receiveBufferSize}" send-buffer-size="${socket.sendBufferSize}" />
<cassandra:keyspace name="${keyspace.name}" action="${keyspace.action}" />
<cassandra:keyspace name="Foo123" action="CREATE_DROP"
durable-writes="true">
<cassandra:replication class="NETWORK_TOPOLOGY_STRATEGY">
<cassandra:data-center replication-factor="${dc1.rf}" name="${dc1.name}"/>
<cassandra:data-center replication-factor="${dc1.rf}" name="${dc2.name}"/>
<cassandra:data-center replication-factor="${dc1.rf}"
name="${dc1.name}" />
<cassandra:data-center replication-factor="${dc1.rf}"
name="${dc2.name}" />
</cassandra:replication>
</cassandra:keyspace>
</cassandra:cluster>
<cassandra:session id="cassandra-session"
keyspace-name="system">
</cassandra:session>
<cassandra:session keyspace-name="system" />
<bean id="cassandraTemplate" class="org.springframework.cassandra.core.CqlTemplate">
<constructor-arg ref="cassandra-session" />
<constructor-arg ref="cassandraSession" />
</bean>
</beans>

View File

@@ -9,8 +9,8 @@
<context:property-placeholder
location="classpath:org.springframework.cassandra.test.integration.support.SpringCassandraBuildProperties.properties" />
<cassandra:cluster id="cassandra-cluster"
contact-points="localhost" port="${build.cassandra.native_transport_port}">
<cassandra:cluster contact-points="localhost"
port="${build.cassandra.native_transport_port}">
<cassandra:local-pooling-options
min-simultaneous-requests="25" max-simultaneous-requests="100"
core-connections="2" max-connections="8" />
@@ -18,16 +18,15 @@
min-simultaneous-requests="25" max-simultaneous-requests="100"
core-connections="1" max-connections="2" />
<cassandra:socket-options
connect-timeout-millis="5000" keep-alive="true" read-timeout-millis="60000" reuse-address="true"
so-linger="60" tcp-no-delay="true" receive-buffer-size="65536"
send-buffer-size="65536" />
connect-timeout-millis="5000" keep-alive="true" read-timeout-millis="60000"
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="xmlconfigtest" />
<cassandra:session keyspace-name="xmlconfigtest" />
<bean id="cassandraTemplate" class="org.springframework.cassandra.core.CqlTemplate">
<constructor-arg ref="cassandra-session" />
<constructor-arg ref="cassandraSession" />
</bean>
</beans>

View File

@@ -0,0 +1,65 @@
package org.springframework.data.cassandra.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.util.StringUtils;
/**
* Parameter used in conjunction with:
* <p/>
* {@link BeanDefinitionBuilder#addConstructorArgReference(String)},
* {@link BeanDefinitionBuilder#addConstructorArgValue(Object)},
* {@link BeanDefinitionBuilder#addPropertyReference(String, String)}, and
* {@link BeanDefinitionBuilder#addPropertyValue(String, Object)}.
* <p/>
* Easy and succinct to create if methods {@link #ref(CharSequence)} or {@link #val(Object)} are used and imported
* statically.
*
* @see BeanDefinitionBuilderArgument#ref(CharSequence)
* @see BeanDefinitionBuilderArgument#val(Object)
*/
public class BeanDefinitionBuilderArgument {
/**
* Returns a {@link BeanDefinitionBuilderArgument} with {@link #reference} equal to <code>true</code>. Convenient if
* imported statically.
*
* @param value The name of the bean reference.
*/
public static BeanDefinitionBuilderArgument ref(CharSequence value) {
return new BeanDefinitionBuilderArgument(true, value);
}
/**
* Returns a {@link BeanDefinitionBuilderArgument} with {@link #reference} equal to <code>false</code>. Convenient if
* imported statically.
*
* @param value The constructor argument's value.
*/
public static BeanDefinitionBuilderArgument val(Object value) {
return new BeanDefinitionBuilderArgument(false, value);
}
protected boolean reference;
protected Object value;
protected BeanDefinitionBuilderArgument(boolean reference, Object value) {
this.reference = reference;
if (this.reference && (value == null || !(value instanceof CharSequence))) {
throw new IllegalArgumentException(String.format(
"reference argument must have value of type CharSequence, not [%s]", value == null ? "null" : value
.getClass().getName()));
}
if (!StringUtils.hasText((CharSequence) value)) {
throw new IllegalArgumentException("given CharSequence has no text");
}
this.value = value;
}
public boolean isReference() {
return reference;
}
public Object getValue() {
return value;
}
}

View File

@@ -0,0 +1,144 @@
package org.springframework.data.cassandra.config;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.util.StringUtils;
public class BeanDefinitionUtils {
/**
* Returns a {@link BeanDefinitionBuilder} iff no {@link BeanDefinition} of the required type is found in the given
* {@link ListableBeanFactory}, otherwise returns <code>null</code>, indicating that at least one existed.
*
* @param factory The {@link ListableBeanFactory} in which to look for the {@link BeanDefinition}, including
* ancestors.
* @param requiredType The {@link BeanDefinition}'s required type.
* @param instantiableType The instantiable type for the {@link BeanDefinitionBuilder}.
* @param constructorArgs Any {@link BeanDefinitionBuilderArgument}s required by the instantiableType's constructor.
* @return A {@link BeanDefinitionBuilder} iff no {@link BeanDefinition} of the required type is found, otherwise
* <code>null</code>.
* @see BeanDefinitionUtils#createBeanDefinitionBuilderIfNoBeanDefinitionOfTypeExists(ListableBeanFactory, Class,
* Class, BeanDefinitionBuilderArgument...)
* @see BeanDefinitionBuilderArgument#ref(Object)
* @see BeanDefinitionBuilderArgument#val(Object)
*/
public static BeanDefinitionBuilder createBeanDefinitionBuilderIfNoBeanDefinitionOfTypeExists(
ListableBeanFactory factory, Class<?> requiredType, Class<?> instantiableType,
BeanDefinitionBuilderArgument... constructorArgs) {
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(factory, requiredType, true, false);
if (names.length > 0) {
return null;
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(instantiableType);
if (constructorArgs == null) {
return builder;
}
for (BeanDefinitionBuilderArgument arg : constructorArgs) {
if (arg.reference) {
builder.addConstructorArgReference(arg.value.toString());
} else {
builder.addConstructorArgValue(arg.value);
}
}
return builder;
}
/**
* Returns the single {@link BeanDefinitionHolder} with the given type, or null of none were found and
* <code>required</code> was <code>false</code>, otherwise throws {@link IllegalArgumentException}.
*
* @param registry The {@link BeanDefinitionRegistry}, often the very same instance as the <code>factor</code>
* parameter.
* @param factory The {@link ListableBeanFactory}, often the very same instance as the <code>registry</code>
* parameter.
* @param type The required {@link BeanDefinition}'s type.
* @param includeNonSingletons Whether to include beans with scope other than <code>singleton</code>
* @param allowEagerInit Whether to allow eager initialization of beans.
* @param required Whether to allow the return of null if none were found.
* @return The {@link BeanDefinitionHolder} or null if none found, depending on the value of <code>required</code>.
* @throws IllegalArgumentException If multiple were found.
* @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean)
*/
public static BeanDefinitionHolder getSingleBeanDefinitionOfType(BeanDefinitionRegistry registry,
ListableBeanFactory factory, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit, boolean required) {
BeanDefinitionHolder[] definitions = getBeanDefinitionsOfType(registry, factory, type, includeNonSingletons,
allowEagerInit);
if (definitions.length == 1) {
return definitions[0];
}
if (definitions.length == 0 && !required) {
return null;
}
String[] names = new String[definitions.length];
for (int i = 0; i < names.length; i++) {
names[i] = definitions[i].getBeanName();
}
throw new IllegalStateException(String.format("expected one bean definition of type [%s], but found %d: %s",
type.getName(), definitions.length, StringUtils.arrayToCommaDelimitedString(names)));
}
/**
* Returns all {@link BeanDefinitionHolder}s with the given type.
*
* @param registry The {@link BeanDefinitionRegistry}, often the very same instance as the <code>factor</code>
* parameter.
* @param factory The {@link ListableBeanFactory}, often the very same instance as the <code>registry</code>
* parameter.
* @param type The required {@link BeanDefinition}'s type.
* @param includeNonSingletons Whether to include beans with scope other than <code>singleton</code>
* @param allowEagerInit Whether to allow eager initialization of beans.
* @param required Whether to allow the return of null if none were found.
* @return The {@link BeanDefinitionHolder}s -- never returns null.
* @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean)
*/
public static BeanDefinitionHolder[] getBeanDefinitionsOfType(BeanDefinitionRegistry registry,
ListableBeanFactory factory, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(factory, type, includeNonSingletons,
allowEagerInit);
if (names.length == 0) {
return new BeanDefinitionHolder[] {};
}
BeanDefinitionHolder[] array = new BeanDefinitionHolder[names.length];
for (int i = 0; i < names.length; i++) {
String name = names[i];
BeanDefinition beanDefinition = null;
while (beanDefinition == null) {
try {
beanDefinition = registry.getBeanDefinition(name);
} catch (NoSuchBeanDefinitionException x) {
if (FactoryBean.class.isAssignableFrom(type)) { // try unmangled BeanFactory-prefixed name
name = name.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
} else {
throw x;
}
}
}
array[i] = new BeanDefinitionHolder(beanDefinition, name);
}
return array;
}
}

View File

@@ -7,10 +7,7 @@ import org.springframework.data.cassandra.convert.CassandraConverter;
import org.springframework.data.cassandra.core.CassandraAdminTemplate;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.EntityMapping;
import org.springframework.data.cassandra.mapping.Mapping;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.datastax.driver.core.KeyspaceMetadata;
import com.datastax.driver.core.Metadata;
@@ -22,8 +19,6 @@ 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 {
@@ -34,42 +29,9 @@ public class CassandraDataSessionFactoryBean extends CassandraSessionFactoryBean
admin = new CassandraAdminTemplate(session, converter);
mapping = mapping == null ? new Mapping() : mapping;
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;
@@ -138,22 +100,4 @@ public class CassandraDataSessionFactoryBean extends CassandraSessionFactoryBean
this.converter = converter;
this.mappingContext = converter.getMappingContext();
}
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;
}
}

View File

@@ -0,0 +1,136 @@
package org.springframework.data.cassandra.config;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.mapping.Table;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Scans packages for Cassandra entities.
*
* @author Matthew T. Adams
*/
public class CassandraEntityClassScanner {
public static Set<Class<?>> scan(String... entityBasePackages) throws ClassNotFoundException {
return new CassandraEntityClassScanner(entityBasePackages).scanForEntityClasses();
}
public static Set<Class<?>> scan(Class<?>... entityBasePackageClasses) throws ClassNotFoundException {
return new CassandraEntityClassScanner(entityBasePackageClasses).scanForEntityClasses();
}
public static Set<Class<?>> scan(Collection<String> entityBasePackages) throws ClassNotFoundException {
return new CassandraEntityClassScanner(entityBasePackages).scanForEntityClasses();
}
public static Set<Class<?>> scan(Collection<String> entityBasePackages, Collection<Class<?>> entityBasePackageClasses)
throws ClassNotFoundException {
return new CassandraEntityClassScanner(entityBasePackages, entityBasePackageClasses).scanForEntityClasses();
}
protected Set<String> entityBasePackages = new HashSet<String>();
protected Set<Class<?>> entityBasePackageClasses = new HashSet<Class<?>>();
protected ClassLoader beanClassLoader;
public CassandraEntityClassScanner() {
}
public CassandraEntityClassScanner(Class<?>... entityBasePackageClasses) {
this(null, Arrays.asList(entityBasePackageClasses));
}
public CassandraEntityClassScanner(String... entityBasePackages) {
this(Arrays.asList(entityBasePackages));
}
public CassandraEntityClassScanner(Collection<String> entityBasePackages) {
this(entityBasePackages, null);
}
public CassandraEntityClassScanner(Collection<String> entityBasePackages,
Collection<Class<?>> entityBasePackageClasses) {
setEntityBasePackages(entityBasePackages);
setEntityBasePackageClasses(entityBasePackageClasses);
}
public Set<String> getEntityBasePackages() {
return Collections.unmodifiableSet(entityBasePackages);
}
public void setEntityBasePackages(Collection<String> entityBasePackages) {
this.entityBasePackages = entityBasePackages == null ? new HashSet<String>() : new HashSet<String>(
entityBasePackages);
}
public Set<Class<?>> getEntityBasePackageClasses() {
return Collections.unmodifiableSet(entityBasePackageClasses);
}
public void setEntityBasePackageClasses(Collection<Class<?>> entityBasePackageClasses) {
this.entityBasePackageClasses = entityBasePackageClasses == null ? new HashSet<Class<?>>() : new HashSet<Class<?>>(
entityBasePackageClasses);
}
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
/**
* Scans the mapping base package for entity classes annotated with {@link Table} or {@link Persistent}.
*
* @see #getEntityBasePackages()
* @return <code>Set&lt;Class&lt;?&gt;&gt;</code> representing the annotated entity classes found.
* @throws ClassNotFoundException
*/
public Set<Class<?>> scanForEntityClasses() throws ClassNotFoundException {
Set<Class<?>> classes = new HashSet<Class<?>>();
for (String basePackage : getEntityBasePackages()) {
classes.addAll(scanBasePackageForEntities(basePackage));
}
for (Class<?> basePackageClass : getEntityBasePackageClasses()) {
classes.addAll(scanBasePackageForEntities(basePackageClass.getPackage().getName()));
}
return classes;
}
protected Set<Class<?>> scanBasePackageForEntities(String basePackage) throws ClassNotFoundException {
HashSet<Class<?>> classes = new HashSet<Class<?>>();
if (StringUtils.hasText(basePackage)) {
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
false);
for (Class<? extends Annotation> annoClass : getEntityAnnotations()) {
componentProvider.addIncludeFilter(new AnnotationTypeFilter(annoClass));
}
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
classes.add(ClassUtils.forName(candidate.getBeanClassName(), beanClassLoader));
}
}
return classes;
}
@SuppressWarnings("unchecked")
public Class<? extends Annotation>[] getEntityAnnotations() {
return new Class[] { Table.class, Persistent.class, PrimaryKeyClass.class };
}
}

View File

@@ -0,0 +1,188 @@
package org.springframework.data.cassandra.config;
import static org.springframework.data.cassandra.config.BeanDefinitionUtils.getBeanDefinitionsOfType;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.data.cassandra.convert.CassandraConverter;
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext;
import org.springframework.util.StringUtils;
import com.datastax.driver.core.Session;
/**
* {@link BeanDefinitionRegistryPostProcessor} that does its best to register any missing Spring Data Cassandra beans
* that can be defaulted. Specifically, it attempts to create default bean definitions for the following required
* interface types via their default implementation types:
* <ul>
* <li>{@link CassandraOperations} via {@link CassandraTemplate}</li>
* <li>{@link CassandraMappingContext} via {@link DefaultCassandraMappingContext}</li>
* <li> {@link CassandraConverter} via {@link MappingCassandraConverter}</li>
* </ul>
* <p/>
* If there are multiple definitions for any type that another type depends on, an {@link IllegalStateException} is
* thrown. For example, if there are two definitions for type {@link CassandraMappingContext} present and no definition
* for type {@link CassandraConverter}, then it's impossible to know which {@link CassandraMappingContext} is to be used
* when creating a default definition for the {@link CassandraConverter}.
* <p/>
* If a single definition of a required type is present, then it is used. For example, if there is already a
* {@link CassandraMappingContext} definition present, then it will be used in the
* {@link DefaultCassandraMappingContext} bean definition.
* <p/>
* It requires that a single {@link Session} or {@link CassandraDataSessionFactoryBean} definition be present. As
* described above, multiple {@link Session} definitions, multiple {@link CassandraDataSessionFactoryBean} definitions,
* or both a {@link Session} and {@link CassandraDataSessionFactoryBean} will cause an {@link IllegalStateException} to
* be thrown.
*
* @author Matthew T. Adams
*/
public class CassandraMappingBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
/**
* Does nothing.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
/**
* Ensures that {@link BeanDefinition}s for a {@link CassandraMappingContext} and a {@link CassandraConverter} exist.
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (!(registry instanceof ListableBeanFactory)) {
return;
}
ListableBeanFactory factory = (ListableBeanFactory) registry;
registerMissingDefaultableBeanDefinitions(registry, factory);
}
protected void registerMissingDefaultableBeanDefinitions(BeanDefinitionRegistry registry, ListableBeanFactory factory) {
// see if any template definitions exist, which requires a converter, which requires a mapping context
BeanDefinitionHolder[] templateBeans = getBeanDefinitionsOfType(registry, factory, CassandraOperations.class, true,
false);
if (templateBeans.length >= 1) {
return;
}
// need a session & converter for the default template
// see if an actual Session definition exists
String sessionBeanName = findSessionBeanName(registry, factory);
// see if any converter bean definitions exist, which requires a mapping context
BeanDefinitionHolder[] converterBeans = getBeanDefinitionsOfType(registry, factory,
MappingCassandraConverter.class, true, false);
if (converterBeans.length == 1) {
registerDefaultTemplate(registry, sessionBeanName, converterBeans[0].getBeanName());
return;
} else if (converterBeans.length > 1) {
// then throw, because we need to create a default converter, but we wouldn't know which mapping context to use
throw new IllegalStateException(String.format(
"found %d beans of type [%s] - can't disambiguate for creation of [%s]", converterBeans.length,
CassandraConverter.class.getName(), CassandraTemplate.class.getName()));
}
// see if any mapping context bean definitions exist
BeanDefinitionHolder[] contextBeans = getBeanDefinitionsOfType(registry, factory, CassandraMappingContext.class,
true, false);
if (contextBeans.length > 1) {
// then throw, because we need to create a default converter, but we wouldn't know which mapping context to use
throw new IllegalStateException(String.format(
"found %d beans of type [%s] - can't disambiguate for creation of [%s]", contextBeans.length,
CassandraMappingContext.class.getName(), MappingCassandraConverter.class.getName()));
}
// create the mapping context if necessary
BeanDefinitionHolder contextBean = contextBeans.length == 1 ? contextBeans[0] : null;
if (contextBean == null) {
contextBean = regsiterDefaultContext(registry);
}
// create the default converter & template bean definitions
BeanDefinitionHolder converter = registerDefaultConverter(registry, contextBean.getBeanName());
registerDefaultTemplate(registry, sessionBeanName, converter.getBeanName());
}
public String findSessionBeanName(BeanDefinitionRegistry registry, ListableBeanFactory factory) {
// first, search for any session and session factory beans
BeanDefinitionHolder[] sessionBeans = getBeanDefinitionsOfType(registry, factory, Session.class, true, false);
BeanDefinitionHolder[] sessionFactoryBeans = getBeanDefinitionsOfType(registry, factory,
CassandraDataSessionFactoryBean.class, true, false);
int sessionCount = sessionBeans.length;
int sessionFactoryCount = sessionFactoryBeans.length;
int totalCount = sessionCount + sessionFactoryCount;
if (totalCount == 0 || totalCount > 1) { // can't create default template -- none or multiple
throw createSessionException(totalCount, Session.class, CassandraDataSessionFactoryBean.class);
}
if (sessionCount == 1) {
return sessionBeans[0].getBeanName();
}
// else it must be the one session factory bean
return sessionFactoryBeans[0].getBeanName();
}
protected IllegalStateException createSessionException(int beanDefinitionCount, Class<?>... types) {
return new IllegalStateException(String.format("found %d beans of type%s [%s] - %s for creation of default [%s]",
beanDefinitionCount, beanDefinitionCount == 1 ? "" : "s", StringUtils.arrayToCommaDelimitedString(types),
beanDefinitionCount == 0 ? "need exactly one" : "can't disambiguate", CassandraTemplate.class.getName()));
}
protected BeanDefinitionHolder regsiterDefaultContext(BeanDefinitionRegistry registry) {
BeanDefinitionHolder contextBean = new BeanDefinitionHolder(BeanDefinitionBuilder.genericBeanDefinition(
DefaultCassandraMappingContext.class).getBeanDefinition(), DefaultDataBeanNames.CONTEXT);
registry.registerBeanDefinition(contextBean.getBeanName(), contextBean.getBeanDefinition());
return contextBean;
}
public BeanDefinitionHolder registerDefaultConverter(BeanDefinitionRegistry registry, String contextBeanName) {
BeanDefinitionBuilder converterBeanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(
MappingCassandraConverter.class).addConstructorArgReference(contextBeanName);
BeanDefinitionHolder beanDefinition = new BeanDefinitionHolder(converterBeanDefinitionBuilder.getBeanDefinition(),
DefaultDataBeanNames.CONVERTER);
registry.registerBeanDefinition(beanDefinition.getBeanName(), beanDefinition.getBeanDefinition());
return beanDefinition;
}
public BeanDefinitionHolder registerDefaultTemplate(BeanDefinitionRegistry registry, String sessionBeanName,
String converterBeanName) {
BeanDefinitionBuilder templateBeanDefinitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(CassandraTemplate.class).addConstructorArgReference(sessionBeanName)
.addConstructorArgReference(converterBeanName);
BeanDefinition beanDefinition = templateBeanDefinitionBuilder.getBeanDefinition();
BeanDefinitionHolder template = new BeanDefinitionHolder(beanDefinition, DefaultDataBeanNames.TEMPLATE);
registry.registerBeanDefinition(template.getBeanName(), template.getBeanDefinition());
return template;
}
}

View File

@@ -4,6 +4,7 @@ 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";
public static final String DATA_TEMPLATE = "cassandraTemplate";
public static final String CONVERTER = "cassandraConverter";
public static final String CONTEXT = "cassandraMapping";
}

View File

@@ -15,18 +15,12 @@
*/
package org.springframework.data.cassandra.config.java;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.cassandra.config.java.AbstractClusterConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.cassandra.config.CassandraDataSessionFactoryBean;
import org.springframework.data.cassandra.config.CassandraEntityClassScanner;
import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.convert.CassandraConverter;
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
@@ -34,12 +28,8 @@ import org.springframework.data.cassandra.core.CassandraAdminOperations;
import org.springframework.data.cassandra.core.CassandraAdminTemplate;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext;
import org.springframework.data.cassandra.mapping.Mapping;
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.mapping.Table;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Base class for Spring Data Cassandra configuration using JavaConfig.
@@ -54,7 +44,6 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC
protected abstract String getKeyspaceName();
protected ClassLoader beanClassLoader;
protected Mapping mapping = new Mapping();
/**
* The {@link SchemaAction} to perform. Defaults to {@link SchemaAction#NONE}.
@@ -64,11 +53,11 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC
}
/**
* The base package to scan for entities annotated with {@link Table} annotations. By default, returns the package
* name of {@literal this} (<code>this.getClass().getPackage().getName()</code>).
* The base packages to scan for entities annotated with {@link Table} annotations. By default, returns the package
* name of {@literal this} (<code>this.getClass().getPackage().getName()</code>). This method must never return null.
*/
public String getEntityBasePackage() {
return getClass().getPackage().getName();
public String[] getEntityBasePackages() {
return new String[] { getClass().getPackage().getName() };
}
@Bean
@@ -77,15 +66,12 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC
CassandraDataSessionFactoryBean bean = new CassandraDataSessionFactoryBean();
bean.setCluster(cluster().getObject());
bean.setConverter(converter());
bean.setConverter(cassandraConverter());
bean.setSchemaAction(getSchemaAction());
bean.setKeyspaceName(getKeyspaceName());
bean.setStartupScripts(getStartupScripts());
bean.setShutdownScripts(getShutdownScripts());
bean.setEntityClassLoader(beanClassLoader);
bean.setMapping(mapping);
return bean;
}
@@ -96,7 +82,7 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC
*/
@Bean
public CassandraAdminOperations cassandraTemplate() throws Exception {
return new CassandraAdminTemplate(session().getObject(), converter());
return new CassandraAdminTemplate(session().getObject(), cassandraConverter());
}
/**
@@ -105,59 +91,21 @@ public abstract class AbstractSpringDataCassandraConfiguration extends AbstractC
* @throws ClassNotFoundException
*/
@Bean
public CassandraMappingContext cassandraMappingContext() throws ClassNotFoundException {
DefaultCassandraMappingContext context = new DefaultCassandraMappingContext();
context.setInitialEntitySet(getInitialEntitySet());
return context;
public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
DefaultCassandraMappingContext bean = new DefaultCassandraMappingContext();
bean.setInitialEntitySet(CassandraEntityClassScanner.scan(getEntityBasePackages()));
bean.setBeanClassLoader(beanClassLoader);
return bean;
}
/**
* Return the {@link CassandraConverter} instance to convert Rows to Objects, Objects to BuiltStatements
*
* @throws ClassNotFoundException
*/
@Bean
public CassandraConverter converter() throws ClassNotFoundException {
MappingCassandraConverter converter = new MappingCassandraConverter(cassandraMappingContext());
converter.setBeanClassLoader(beanClassLoader);
return converter;
}
/**
* Scans the mapping base package for entity classes annotated with {@link Table} or {@link Persistent}.
*
* @see #getEntityBasePackage()
* @return <code>Set&lt;Class&lt;?&gt;&gt;</code> representing the annotated entity classes found.
* @throws ClassNotFoundException
*/
protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
String basePackage = getEntityBasePackage();
Set<Class<?>> initialEntitySet = new HashSet<Class<?>>();
if (StringUtils.hasText(basePackage)) {
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
false);
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Table.class));
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
componentProvider.addIncludeFilter(new AnnotationTypeFilter(PrimaryKeyClass.class));
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
Class<?> clazz = ClassUtils.forName(candidate.getBeanClassName(), beanClassLoader);
initialEntitySet.add(clazz);
}
}
processMappingOverrides(initialEntitySet);
return initialEntitySet;
}
protected void processMappingOverrides(Set<Class<?>> entityTypes) {
// TODO: search for external entity mapping info (xml/properties/yaml/etc) here & update this.mapping
// similar to JPA's or JDO's external metadata search algorithms
public CassandraConverter cassandraConverter() throws Exception {
return new MappingCassandraConverter(cassandraMapping());
}
@Override

View File

@@ -1,6 +1,9 @@
package org.springframework.data.cassandra.config.xml;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.cassandra.config.xml.CassandraClusterParser;
import org.w3c.dom.Element;
/**
* Spring Data Cassandra XML namespace parser for the &lt;cluster&gt; element.
@@ -8,4 +11,12 @@ import org.springframework.cassandra.config.xml.CassandraClusterParser;
* @author Matthew T. Adams
*/
public class CassandraDataClusterParser extends CassandraClusterParser {
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext);
return super.parseInternal(element, parserContext);
}
}

View File

@@ -36,5 +36,7 @@ public class CassandraDataNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser("cluster", new CassandraDataClusterParser());
registerBeanDefinitionParser("session", new CassandraDataSessionParser());
registerBeanDefinitionParser("template", new CassandraDataTemplateParser());
registerBeanDefinitionParser("converter", new CassandraMappingConverterParser());
registerBeanDefinitionParser("mapping", new CassandraMappingContextParser());
}
}

View File

@@ -1,20 +1,16 @@
package org.springframework.data.cassandra.config.xml;
import static org.springframework.cassandra.config.xml.ParsingUtils.*;
import java.util.HashSet;
import java.util.Set;
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.addRequiredPropertyReference;
import static org.springframework.cassandra.config.xml.ParsingUtils.addRequiredPropertyValue;
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.DefaultDataBeanNames;
import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.mapping.EntityMapping;
import org.springframework.data.cassandra.mapping.Mapping;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
@@ -30,6 +26,14 @@ public class CassandraDataSessionParser extends CassandraSessionParser {
return CassandraDataSessionFactoryBean.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);
CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext);
}
@Override
protected void parseUnhandledSessionElementAttribute(Attr attribute, ParserContext parserContext,
BeanDefinitionBuilder builder) {
@@ -46,55 +50,11 @@ public class CassandraDataSessionParser extends CassandraSessionParser {
}
@Override
protected void parseUnhandledElement(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
protected void setDefaultProperties(BeanDefinitionBuilder builder) {
if ("mapping".equals(element.getLocalName())) {
parseMapping(element, parserContext, builder);
} else {
super.parseUnhandledElement(element, parserContext, builder);
}
}
super.setDefaultProperties(builder);
protected void parseMapping(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// TODO: parse <mapping> attributes here, if there ever are any
Set<EntityMapping> mappings = new HashSet<EntityMapping>();
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);
addRequiredPropertyValue(builder, "schemaAction", SchemaAction.NONE.name());
addRequiredPropertyReference(builder, "converter", DefaultDataBeanNames.CONVERTER);
}
}

View File

@@ -32,6 +32,9 @@ public class CassandraDataTemplateParser extends CassandraTemplateParser {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext);
super.doParse(element, parserContext, builder);
parseConverterAttribute(element, parserContext, builder);

View File

@@ -0,0 +1,87 @@
package org.springframework.data.cassandra.config.xml;
import java.util.HashSet;
import java.util.Set;
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.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.cassandra.config.DefaultDataBeanNames;
import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext;
import org.springframework.data.cassandra.mapping.EntityMapping;
import org.springframework.data.cassandra.mapping.Mapping;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Spring Data Cassandra XML namespace parser for the &lt;mapping&gt; element.
*
* @author Matthew T. Adams
*/
public class CassandraMappingContextParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return DefaultCassandraMappingContext.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.CONTEXT;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext);
parseMapping(element, builder);
}
protected void parseMapping(Element element, BeanDefinitionBuilder builder) {
Set<EntityMapping> mappings = new HashSet<EntityMapping>();
for (Element entity : DomUtils.getChildElementsByTagName(element, "entity")) {
EntityMapping entityMapping = parseEntity(entity);
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);
}
}

View File

@@ -0,0 +1,45 @@
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.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.cassandra.config.DefaultDataBeanNames;
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Spring Data Cassandra XML namespace parser for the &lt;converter&gt; element.
*
* @author Matthew T. Adams
*/
public class CassandraMappingConverterParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return MappingCassandraConverter.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.CONVERTER;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext);
String mappingRef = element.getAttribute("mapping-ref");
if (!StringUtils.hasText(mappingRef)) {
mappingRef = DefaultDataBeanNames.CONTEXT;
}
builder.addConstructorArgReference(mappingRef);
}
}

View File

@@ -0,0 +1,44 @@
package org.springframework.data.cassandra.config.xml;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.data.cassandra.config.CassandraMappingBeanFactoryPostProcessor;
import org.springframework.data.config.BeanComponentDefinitionBuilder;
import org.w3c.dom.Element;
/**
* Ensures that a {@link CassandraMappingBeanFactoryPostProcessor} is registered.
*
* @author Matthew T. Adams
*/
public class CassandraMappingXmlBeanFactoryPostProcessorRegistrar {
/**
* Ensures that a {@link CassandraMappingBeanFactoryPostProcessor} is registered. This method is a no-op if one is
* already registered.
*/
public static void ensureRegistration(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
if (!(registry instanceof GenericApplicationContext)) {
return;
}
ConfigurableListableBeanFactory factory = ((GenericApplicationContext) registry).getBeanFactory();
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(factory,
CassandraMappingBeanFactoryPostProcessor.class, true, false);
if (names.length > 0) {
return;
}
BeanComponentDefinitionBuilder componentBuilder = new BeanComponentDefinitionBuilder(element, parserContext);
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
.genericBeanDefinition(CassandraMappingBeanFactoryPostProcessor.class);
parserContext.registerBeanComponent(componentBuilder.getComponent(definitionBuilder));
}
}

View File

@@ -123,7 +123,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
Assert.notNull(type);
Assert.notNull(id);
CassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(type);
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);
Select select = QueryBuilder.select().countAll().from(entity.getTableName());
appendIdCriteria(select.where(), entity, id);
@@ -152,9 +152,9 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
Assert.notNull(type);
Assert.notNull(id);
CassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(type);
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);
Delete delete = QueryBuilder.delete().all().from(entity.getTableName());
Delete delete = QueryBuilder.delete().from(entity.getTableName());
appendIdCriteria(delete.where(), entity, id);
execute(delete.getQueryString());
@@ -192,7 +192,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
@Override
public String getTableName(Class<?> type) {
return mappingContext.getRequiredPersistentEntity(type).getTableName();
return mappingContext.getPersistentEntity(type).getTableName();
}
@Override
@@ -252,7 +252,7 @@ public class CassandraTemplate extends CqlTemplate implements CassandraOperation
@Override
public <T> List<T> selectBySimpleIds(Class<T> type, Iterable<?> ids) {
CassandraPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(type);
CassandraPersistentEntity<?> entity = mappingContext.getPersistentEntity(type);
if (entity.getIdProperty().isCompositePrimaryKey()) {
throw new IllegalArgumentException(String.format(

View File

@@ -4,7 +4,6 @@ import java.util.Collection;
import org.springframework.cassandra.core.keyspace.CreateTableSpecification;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.util.TypeInformation;
import com.datastax.driver.core.TableMetadata;
@@ -59,22 +58,17 @@ public interface CassandraMappingContext extends
boolean usesTable(TableMetadata table);
/**
* Returns the {@link CassandraPersistentEntity} for the given type. If it doesn't exist, this method throws
* {@link IllegalArgumentException}.
* Returns the existing {@link CassandraPersistentEntity} for the given {@link Class}. If it is not yet known to this
* {@link CassandraMappingContext}, an {@link IllegalArgumentException} is thrown.
*
* @param type The Java type of the persistent entity.
* @return The {@link CassandraPersistentEntity} describing the persistent Java type.
* @throws IllegalArgumentException if the persistent entity is unknown
* @param type The class of the existing persistent entity.
* @return The existing persistent entity.
*/
public CassandraPersistentEntity<?> getRequiredPersistentEntity(Class<?> type);
CassandraPersistentEntity<?> getExistingPersistentEntity(Class<?> type);
/**
* Returns the {@link CassandraPersistentEntity} for the given type. If it doesn't exist, this method throws
* {@link IllegalArgumentException}.
*
* @param type The {@link TypeInformation} of the persistent entity.
* @return The {@link CassandraPersistentEntity} describing the persistent Java type.
* @throws IllegalArgumentException if the persistent entity is unknown
* Returns whether this {@link CassandraMappingContext} already contains a {@link CassandraPersistentEntity} for the
* given type.
*/
public CassandraPersistentEntity<?> getRequiredPersistentEntity(TypeInformation<?> type);
boolean contains(Class<?> type);
}

View File

@@ -37,6 +37,8 @@ import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import com.datastax.driver.core.TableMetadata;
@@ -52,9 +54,14 @@ public class DefaultCassandraMappingContext extends
CassandraMappingContext, ApplicationContextAware {
protected ApplicationContext context;
protected Mapping mapping = new Mapping();
protected ClassLoader beanClassLoader;
// useful caches
protected Map<String, Set<CassandraPersistentEntity<?>>> entitySetsByTableName = new HashMap<String, Set<CassandraPersistentEntity<?>>>();
protected Set<CassandraPersistentEntity<?>> nonPrimaryKeyEntities = new HashSet<CassandraPersistentEntity<?>>();
protected Set<CassandraPersistentEntity<?>> primaryKeyEntities = new HashSet<CassandraPersistentEntity<?>>();
protected Map<Class<?>, CassandraPersistentEntity<?>> entitiesByType = new HashMap<Class<?>, CassandraPersistentEntity<?>>();
/**
* Creates a new {@link DefaultCassandraMappingContext}.
@@ -63,6 +70,14 @@ public class DefaultCassandraMappingContext extends
setSimpleTypeHolder(new CassandraSimpleTypeHolder());
}
@Override
public void initialize() {
super.initialize();
processMappingOverrides();
}
@Override
public Collection<CassandraPersistentEntity<?>> getPersistentEntities() {
return getPersistentEntities(false);
@@ -123,6 +138,8 @@ public class DefaultCassandraMappingContext extends
nonPrimaryKeyEntities.add(entity);
}
entitiesByType.put(entity.getType(), entity);
return entity;
}
@@ -184,28 +201,65 @@ public class DefaultCassandraMappingContext extends
return spec;
}
@Override
public CassandraPersistentEntity<?> getRequiredPersistentEntity(Class<?> type) {
public void setMapping(Mapping mapping) {
CassandraPersistentEntity<?> entity = getPersistentEntity(type);
Assert.notNull(mapping);
if (entity == null) {
throw new IllegalArgumentException(String.format("no persistence metadata found for type [%s]", type.getName()));
this.mapping = mapping;
}
protected void processMappingOverrides() {
if (mapping == null) {
return;
}
return entity;
for (EntityMapping entityMapping : mapping.getEntityMappings()) {
if (entityMapping == null) {
continue;
}
String entityClassName = entityMapping.getEntityClassName();
Class<?> entityClass;
try {
entityClass = ClassUtils.forName(entityClassName, beanClassLoader);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(String.format("unknown persistent entity name [%s]", entityClassName), e);
}
CassandraPersistentEntity<?> entity = 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);
}
}
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
@Override
public CassandraPersistentEntity<?> getRequiredPersistentEntity(TypeInformation<?> type) {
public CassandraPersistentEntity<?> getExistingPersistentEntity(Class<?> type) {
CassandraPersistentEntity<?> entity = getPersistentEntity(type);
if (entity == null) {
throw new IllegalArgumentException(String.format("no persistence metadata found for type [%s]",
type.getActualType()));
CassandraPersistentEntity<?> entity = entitiesByType.get(type);
if (entity != null) {
return entity;
}
return entity;
throw new IllegalArgumentException(String.format("unknown persistent type [%s]", type.getName()));
}
@Override
public boolean contains(Class<?> type) {
return entitiesByType.containsKey(type);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.cassandra.repository.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.cassandra.config.xml.ParsingUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.data.cassandra.config.DefaultDataBeanNames;
import org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
@@ -52,7 +53,7 @@ public class CassandraRepositoryConfigurationExtension extends RepositoryConfigu
Element element = config.getElement();
ParsingUtils.addOptionalPropertyReference(builder, "cassandraTemplate", element, CASSANDRA_TEMPLATE_REF,
"cassandra-template");
DefaultDataBeanNames.TEMPLATE);
}
@Override

View File

@@ -452,8 +452,6 @@ Arbitrary CQL script to be executed against the session's keyspace during bean d
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="mapping" type="mappingType" minOccurs="0"
maxOccurs="1" />
</xsd:sequence>
<xsd:attribute name="id" type="xsd:ID" use="optional">
@@ -482,7 +480,7 @@ The name of a Cassandra Keyspace. No default; for the system keyspace, use the
use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to a CassandraConverter; default is "cassandra-converter".
The reference to a CassandraConverter; default is "cassandraConverter".
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -500,7 +498,7 @@ The schema action to perform; default is NONE.
<xsd:attribute name="id" type="xsd:ID" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the template; default is "cassandra-template".
The name of the template; default is "cassandraTemplate".
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -515,7 +513,7 @@ The reference to a Cassandra session; default is "cassandra-session".
use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to a CassandraConverter; default is "cassandra-converter".
The reference to a CassandraConverter; default is "cassandraConverter".
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -629,13 +627,6 @@ The replication factor for the data center.
<xsd:union memberTypes="xsd:string" />
</xsd:simpleType>
<xsd:complexType name="mappingType">
<xsd:sequence>
<xsd:element name="entity" type="entityType" minOccurs="0"
maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="entityType">
<xsd:sequence>
<xsd:element name="table" type="tableType" minOccurs="0"
@@ -676,11 +667,10 @@ Table name override.
</xsd:simpleType>
<xsd:attributeGroup name="cassandra-repository-attributes">
<xsd:attribute name="cassandra-template-ref" type="cassandraTemplateRef"
default="cassandra-template">
<xsd:attribute name="cassandra-template-ref" type="cassandraTemplateRef">
<xsd:annotation>
<xsd:documentation><![CDATA[
The reference to a cassandraTemplate. Will default to 'cassandra-template'.
The reference to a cassandraTemplate. Will default to 'cassandraTemplate'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -696,4 +686,65 @@ The reference to a cassandraTemplate. Will default to 'cassandra-template'.
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="mapping">
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines a CassandraMappingContext for holding rich entity mapping information.
]]></xsd:documentation>
<xsd:appinfo>
<tool:exports
type="org.springframework.data.cassandra.mapping.CassandraMappingContext" />
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="entity" type="entityType" minOccurs="0"
maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="entity-base-packages" type="xsd:string"
use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The comma-delimited base packages in which to scan for entities and their mapping information.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="converter">
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines a CassandraConverter for getting rich mapping functionality.
]]></xsd:documentation>
<xsd:appinfo>
<tool:exports
type="org.springframework.data.cassandra.convert.CassandraConverter" />
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="mapping-ref" type="mappingContextRef"
use="optional">
<xsd:annotation>
<xsd:documentation
source="org.springframework.data.cassandra.mapping.CassandraMappingContext"><![CDATA[
The reference to a CassandraMappingContext. Will default to 'cassandraMapping'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="mappingContextRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to
type="org.springframework.data.cassandra.mapping.CassandraMappingContext" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string" />
</xsd:simpleType>
</xsd:schema>

View File

@@ -69,8 +69,8 @@ public class CommentRepositoryJavaConfigIntegrationTests extends AbstractSpringD
}
@Override
public String getEntityBasePackage() {
return Comment.class.getPackage().getName();
public String[] getEntityBasePackages() {
return new String[] { Comment.class.getPackage().getName() };
}
}

View File

@@ -0,0 +1,54 @@
package org.springframework.data.cassandra.test.integration.mappingcontext;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
public class MappingContextIntegrationTests {
public static class Transient {
}
@Table
public static class X {
@PrimaryKey
String key;
}
@Table
public static class Y {
@PrimaryKey
String key;
}
DefaultCassandraMappingContext ctx = new DefaultCassandraMappingContext();
@Test
// TODO: (expected = MappingException.class)
public void testGetPersistentEntityOfTransientType() {
// TODO: when entity verification is added (DATACASS-85), this should throw a MappingException
CassandraPersistentEntity<?> entity = ctx.getPersistentEntity(Transient.class);
// TODO: remove following lines after DATACASS-85
assertNotNull(entity);
assertEquals(Transient.class.getSimpleName().toLowerCase(), entity.getTableName());
}
@Test
public void testGetExistingPersistentEntityHappyPath() {
ctx.getPersistentEntity(X.class);
assertTrue(ctx.contains(X.class));
assertNotNull(ctx.getExistingPersistentEntity(X.class));
assertFalse(ctx.contains(Y.class));
}
}

View File

@@ -0,0 +1,28 @@
package org.springframework.data.cassandra.test.integration.minimal.config;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.test.integration.minimal.config.entities.AbsMin;
import org.springframework.data.cassandra.test.integration.support.AbstractSpringDataEmbeddedCassandraIntegrationTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class AbsoluteMinimumXmlConfigIntegrationTest extends AbstractSpringDataEmbeddedCassandraIntegrationTest {
@Autowired
CassandraMappingContext context;
@Test
public void test() {
assertNotNull(context);
context.getPersistentEntity(AbsMin.class);
}
}

View File

@@ -0,0 +1,12 @@
package org.springframework.data.cassandra.test.integration.minimal.config.entities;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
@Table
public class AbsMin {
@PrimaryKey
String key;
}

View File

@@ -0,0 +1,6 @@
package org.springframework.data.cassandra.test.integration.minimal.config.entities;
import org.springframework.data.cassandra.repository.CassandraRepository;
public interface AbsMinRepository extends CassandraRepository<AbsMin, String> {
}

View File

@@ -0,0 +1,47 @@
package org.springframework.data.cassandra.test.integration.multipackagescanning;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.HashSet;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.cassandra.config.CassandraEntityClassScanner;
import org.springframework.data.cassandra.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext;
import org.springframework.data.cassandra.test.integration.multipackagescanning.first.First;
import org.springframework.data.cassandra.test.integration.multipackagescanning.second.Second;
import org.springframework.data.cassandra.test.integration.multipackagescanning.third.Third;
public class MultipackageScanningIntegrationTests {
DefaultCassandraMappingContext mapping;
String pkg = getClass().getPackage().getName();
@Before
public void before() throws ClassNotFoundException {
mapping = new DefaultCassandraMappingContext();
mapping.setInitialEntitySet(CassandraEntityClassScanner.scan(pkg + ".first", pkg + ".second"));
mapping.initialize();
}
@Test
public void test() {
Collection<CassandraPersistentEntity<?>> entities = mapping.getPersistentEntities();
Collection<Class<?>> types = new HashSet<Class<?>>(entities.size());
for (CassandraPersistentEntity<?> entity : entities) {
types.add(entity.getType());
}
assertTrue(types.contains(First.class));
assertTrue(types.contains(Second.class));
assertFalse(types.contains(Third.class));
assertFalse(types.contains(Top.class));
}
}

View File

@@ -0,0 +1,11 @@
package org.springframework.data.cassandra.test.integration.multipackagescanning;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
@Table
public class Top {
@PrimaryKey
String key;
}

View File

@@ -0,0 +1,11 @@
package org.springframework.data.cassandra.test.integration.multipackagescanning.first;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
@Table
public class First {
@PrimaryKey
String key;
}

View File

@@ -0,0 +1,11 @@
package org.springframework.data.cassandra.test.integration.multipackagescanning.second;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
@Table
public class Second {
@PrimaryKey
String key;
}

View File

@@ -0,0 +1,11 @@
package org.springframework.data.cassandra.test.integration.multipackagescanning.third;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
@Table
public class Third {
@PrimaryKey
String key;
}

View File

@@ -68,8 +68,8 @@ public class UserRepositoryJavaConfigIntegrationTests extends AbstractSpringData
}
@Override
public String getEntityBasePackage() {
return User.class.getPackage().getName();
public String[] getEntityBasePackages() {
return new String[] { User.class.getPackage().getName() };
}
}

View File

@@ -66,8 +66,8 @@ public class CassandraDataOperationsTest extends AbstractSpringDataEmbeddedCassa
}
@Override
public String getEntityBasePackage() {
return Book.class.getPackage().getName();
public String[] getEntityBasePackages() {
return new String[] { Book.class.getPackage().getName() };
}
}

View File

@@ -1,33 +1,34 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cass="http://www.springframework.org/schema/data/cassandra"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util-3.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">
<import resource="classpath:/spring-data-cassandra-basic.xml" />
<cassandra:cluster id="cassandra-cluster"
port="${cassandra.native_transport_port}">
<cass:mapping
entity-base-packages="org.springframework.data.cassandra.test.integration.composites">
<cass:entity
class="org.springframework.data.cassandra.test.integration.composites.Comment">
<cass:table name="comments_x" />
</cass:entity>
</cass:mapping>
<cassandra:keyspace name="CommentRepositoryXmlConfigIntegrationTests"
<cass:cluster port="${cassandra.native_transport_port}">
<cass:keyspace name="CommentRepositoryXmlConfigIntegrationTests"
action="CREATE" durable-writes="true">
</cassandra:keyspace>
</cassandra:cluster>
</cass:keyspace>
</cass:cluster>
<cassandra:session id="cassandra-session"
cluster-ref="cassandra-cluster" keyspace-name="CommentRepositoryXmlConfigIntegrationTests"
cassandra-converter-ref="cassandra-converter" schema-action="CREATE">
<cassandra:mapping>
<cassandra:entity
class="org.springframework.data.cassandra.test.integration.composites.Comment">
<cassandra:table name="comments" />
</cassandra:entity>
</cassandra:mapping>
</cassandra:session>
<cass:session keyspace-name="CommentRepositoryXmlConfigIntegrationTests"
schema-action="CREATE">
</cass:session>
<cassandra:repositories
<cass:repositories
base-package="org.springframework.data.cassandra.test.integration.composites" />
</beans>

View File

@@ -11,9 +11,8 @@
<context:property-placeholder
location="classpath:/org/springframework/data/cassandra/test/integration/config/cassandra.properties" />
<cass:cluster id="cassandra-cluster"
contact-points="${cassandra.contactPoints}" port="${cassandra.native_transport_port}"
compression="SNAPPY">
<cass:cluster contact-points="${cassandra.contactPoints}"
port="${cassandra.native_transport_port}" compression="SNAPPY">
<cass:local-pooling-options
min-simultaneous-requests="25" max-simultaneous-requests="100"
core-connections="2" max-connections="8" />
@@ -27,21 +26,13 @@
durable-writes="true" />
</cass:cluster>
<!-- TODO: not require that this bean be defined -->
<bean id="cassandra-mapping"
class="org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext"/>
<!-- TODO: not require that these beans be defined -->
<cass:mapping />
<cass:converter />
<!-- TODO: not require that this bean be defined -->
<bean id="cassandra-converter"
class="org.springframework.data.cassandra.convert.MappingCassandraConverter">
<constructor-arg ref="cassandra-mapping" />
</bean>
<cass:session keyspace-name="${cassandra.keyspace}"
schema-action="NONE" />
<cass:session id="cassandra-session" keyspace-name="${cassandra.keyspace}"
schema-action="NONE" cluster-ref="cassandra-cluster"
cassandra-converter-ref="cassandra-converter">
</cass:session>
<cass:template session-ref="cassandra-session" />
<cass:template />
</beans>

View File

@@ -0,0 +1,22 @@
<?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:cass="http://www.springframework.org/schema/data/cassandra"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util-3.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">
<!-- this is needed just so it runs correctly as part of the build, so ignore it & the port attribute of the cluster below -->
<context:property-placeholder
location="classpath:/spring-data-cassandra-build.properties" />
<cass:cluster port="${cassandra.native_transport_port}" />
<cass:session keyspace-name="system" />
<cass:repositories
base-package="org.springframework.data.cassandra.test.integration.minimal.config" />
</beans>

View File

@@ -1,7 +1,8 @@
<?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" xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cass="http://www.springframework.org/schema/data/cassandra"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
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
@@ -11,25 +12,24 @@
<import resource="classpath:/spring-data-cassandra-basic.xml" />
<cassandra:cluster id="cassandra-cluster"
port="${cassandra.native_transport_port}">
<cass:mapping
entity-base-packages="org.springframework.data.cassandra.test.integration.repository">
<cass:entity
class="org.springframework.data.cassandra.test.integration.repository.User">
<cass:table name="users_x" />
</cass:entity>
</cass:mapping>
<cassandra:keyspace name="UserRepositoryXmlConfigIntegrationTests"
<cass:cluster port="${cassandra.native_transport_port}">
<cass:keyspace name="UserRepositoryXmlConfigIntegrationTests"
action="CREATE" durable-writes="true">
</cassandra:keyspace>
</cassandra:cluster>
</cass:keyspace>
</cass:cluster>
<cassandra:session id="cassandra-session"
cluster-ref="cassandra-cluster" keyspace-name="UserRepositoryXmlConfigIntegrationTests"
cassandra-converter-ref="cassandra-converter" schema-action="CREATE">
<cassandra:mapping>
<cassandra:entity
class="org.springframework.data.cassandra.test.integration.repository.User">
<cassandra:table name="users_x" />
</cassandra:entity>
</cassandra:mapping>
</cassandra:session>
<cass:session keyspace-name="UserRepositoryXmlConfigIntegrationTests"
schema-action="CREATE">
</cass:session>
<cassandra:repositories
<cass:repositories
base-package="org.springframework.data.cassandra.test.integration.repository" />
</beans>

View File

@@ -1,6 +1,6 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cass="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
@@ -10,15 +10,8 @@
<context:property-placeholder
location="classpath:/spring-data-cassandra-build.properties" />
<bean id="cassandra-mapping"
class="org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext" />
<cass:converter mapping-ref="cassandraMapping"/>
<bean id="cassandra-converter"
class="org.springframework.data.cassandra.convert.MappingCassandraConverter">
<constructor-arg ref="cassandra-mapping" />
</bean>
<cassandra:template id="cassandra-template"
cassandra-converter-ref="cassandra-converter" session-ref="cassandra-session" />
<cass:template />
</beans>