Merge branch 'master' of https://github.com/spring-projects/spring-data-cassandra.git
This commit is contained in:
91
README.md
91
README.md
@@ -2,16 +2,19 @@
|
||||
|
||||
## Quick Start
|
||||
|
||||
To begin working with ``spring-cassandra`` and ``spring-data-cassandra`` add the Spring Maven Repository to your ``pom.xml``.
|
||||
To begin working with ``spring-cassandra`` or ``spring-data-cassandra``, add the Spring Maven Snapshot Repository to your ``pom.xml``.
|
||||
|
||||
<repository>
|
||||
<id>spring-libs-snapshot</id>
|
||||
<url>http://repo.spring.io/libs-snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
|
||||
Then include the latest and greatest JAR into your project dependencies.
|
||||
### CQL Only (spring-cassandra)
|
||||
|
||||
**CQL Only**
|
||||
*Maven Coordinates*
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
@@ -19,7 +22,41 @@ Then include the latest and greatest JAR into your project dependencies.
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
**CQL and Object Mapping**
|
||||
*Minimal Spring XML Configuration*
|
||||
|
||||
<cql:cluster />
|
||||
<cql:session keyspace-name="sensors" />
|
||||
<cql:template />
|
||||
|
||||
*Minimal Spring JavaConfig*
|
||||
|
||||
@Configuration
|
||||
public class MyConfig extends AbstractSessionConfiguration {
|
||||
|
||||
@Override
|
||||
public String getKeyspaceName() {
|
||||
return "sensors";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CqlOperations cqlTemplate() {
|
||||
return new CqlTemplate(session.getObject());
|
||||
}
|
||||
}
|
||||
|
||||
*Application Class*
|
||||
|
||||
public class SensorService {
|
||||
|
||||
@Autowired
|
||||
CqlOperations template;
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
### CQL and Object Mapping (spring-data-cassandra)
|
||||
|
||||
*Maven Coordinates*
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
@@ -27,10 +64,39 @@ Then include the latest and greatest JAR into your project dependencies.
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
*Minimal Spring XML Configuration*
|
||||
|
||||
<cassandra:cluster />
|
||||
<cassandra:session keyspace-name="foobar" />
|
||||
<cassandra:repositories base-package="org.example.domain" />
|
||||
|
||||
*Minimal Spring JavaConfig*
|
||||
|
||||
@Configuration
|
||||
@EnableCassandraRepositories(basePackage = "org.example.domain")
|
||||
public class MyConfig extends AbstractSpringDataCassandraConfiguration {
|
||||
|
||||
@Override
|
||||
public String getKeyspaceName() {
|
||||
return "foobar";
|
||||
}
|
||||
}
|
||||
|
||||
*Application Class*
|
||||
|
||||
public class SensorService {
|
||||
|
||||
@Autowired
|
||||
SensorRepository repo;
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
## Release Preview
|
||||
|
||||
The goal of this release preview is to publish the pieces of spring-data-cassandra as they become available
|
||||
so that user's of the module can start to familiarize themselves with the components, and ultimately to provide
|
||||
so that users of the module can start to familiarize themselves with the components, and ultimately to provide
|
||||
the development team feedback. We hope this iterative approach produces the most usable and developer friendly
|
||||
``spring-data-cassandra`` repository.
|
||||
|
||||
@@ -72,9 +138,9 @@ create more than one ``CqlTemplate`` (one per session, one session per keyspace)
|
||||
|
||||
Here are some considerations when designing your application for use with ``spring-cassandra``.
|
||||
|
||||
* When creating a template, wire in a single ``Session`` per keyspace. _Remember, ``Session`` is threadsafe, so only use one session per keyspace!_
|
||||
* Cassandra's ``Session`` object is thread-safe, so you only need one per application & keyspace.
|
||||
* Do not issue ``USE <keyspace>`` commands on your session; instead, _configure_ the keyspace name you intend to use.
|
||||
* When creating a template, wire in a single ``Session`` per keyspace.
|
||||
* ``Session`` is threadsafe, so only use one per keyspace per application context!
|
||||
* __Do not issue__ ``USE <keyspace>`` __commands__ on your session; instead, _configure_ the keyspace name you intend to use.
|
||||
* The DataStax Java Driver handles all failover and retry logic for you. Become familiar with the [Driver Documentation](http://www.datastax.com/documentation/developer/java-driver/1.0/webhelp/index.html), which will help you configure your ``Cluster``.
|
||||
* If you are using a Cassandra ``Cluster`` spanning multiple data centers, please be insure to include hosts from all data centers in your contact points.
|
||||
|
||||
@@ -84,7 +150,7 @@ We have included a variety of overloaded ``ingest()`` methods in ``CqlTemplate``
|
||||
|
||||
### What's Next (early Q1 - 2014): Spring _Data_ Cassandra
|
||||
|
||||
The next round of work to do is to complete module ``spring-data-cassandra``, while taking feedback from the community's use of module ``spring-cassandra``.
|
||||
The next round of work to do is to complete module ``spring-data-cassandra``, while taking feedback from the community's use of module ``spring-cassandra``. We are already well on our way to completion.
|
||||
|
||||
#### Cassandra Repository
|
||||
|
||||
@@ -101,7 +167,7 @@ This is another Spring template class to help you with all of your keyspace and
|
||||
|
||||
#### Official Reference Guide
|
||||
|
||||
Once we have all the inner workings of the ``CassandraRepository`` interface completed, we will publish a full Reference Guide on using all of the features in ``spring-data-cassandra``.
|
||||
Once we have all the inner workings of the ``CassandraRepository`` interface completed, we will publish a full reference guide on using all of the features in ``spring-data-cassandra``.
|
||||
|
||||
## CqlTemplate Examples
|
||||
|
||||
@@ -163,9 +229,8 @@ following artifacts (or more recent versions thereof):
|
||||
* Datastax Java Driver 1.x
|
||||
* JDK 1.6+
|
||||
|
||||
The GA release is expected as part of the as-yet unnamed fourth Spring
|
||||
Data Release Train "D", following Spring Data Release Train
|
||||
[Codd](https://github.com/spring-projects/spring-data-commons/wiki/Release-Train-Codd).
|
||||
The GA release is expected as part of the Spring
|
||||
Data release train [Dijkstra](https://github.com/spring-projects/spring-data-commons/wiki/Release-Train-Dijkstra).
|
||||
|
||||
|
||||
## Cassandra 2.x
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package org.springframework.cassandra.core;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.cassandra.core.cql.CqlStringUtils;
|
||||
|
||||
/**
|
||||
* This encapsulates the logic for CQL identifiers.
|
||||
*
|
||||
* @author John McPeek
|
||||
*
|
||||
*/
|
||||
public class CqlIdentifier {
|
||||
public static final String UNQUOTED_IDENTIFIER_REGEX = "[a-zA-Z_][a-zA-Z0-9_]*";
|
||||
public static final Pattern UNQUOTED_IDENTIFIER_PATTERN = Pattern.compile(UNQUOTED_IDENTIFIER_REGEX);
|
||||
public static final String QUOTED_IDENTIFIER_REGEX = "[a-zA-Z_]([a-zA-Z0-9_]|\"{2}+)*";
|
||||
public static final Pattern QUOTED_IDENTIFIER_PATTERN = Pattern.compile(QUOTED_IDENTIFIER_REGEX);
|
||||
|
||||
private String name;
|
||||
private boolean quoted;
|
||||
|
||||
public CqlIdentifier(String identifier) {
|
||||
this(identifier, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the given string as a legal Cassandra identifier.
|
||||
* <ul>
|
||||
* <li>If the given identifier is a legal quoted identifier or forceQuote is true, it is set encased in double quotes.
|
||||
* </li>
|
||||
* <li>If the given identifier is a legal unquoted identifier, it is set unchanged.</li>
|
||||
* <li>If the given identifier is illegal, an {@link IllegalArgumentException} is thrown.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public CqlIdentifier(String name, boolean forceQuoting) {
|
||||
if (isUnquotedIdentifier(name) && forceQuoting == false) {
|
||||
this.name = name;
|
||||
} else if (isQuotedIdentifier(name)) {
|
||||
this.name = name;
|
||||
quoted = true;
|
||||
} else {
|
||||
throw new IllegalArgumentException("[" + name + "] is not a valid CQL quoted or unquoted identifier");
|
||||
}
|
||||
}
|
||||
|
||||
public String toCql() {
|
||||
String id = quoted ? CqlStringUtils.doubleQuote(name) : name;
|
||||
return id;
|
||||
}
|
||||
|
||||
public StringBuilder toCql(StringBuilder sb) {
|
||||
return sb.append(toCql());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toCql();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isQuoted() {
|
||||
return quoted;
|
||||
}
|
||||
|
||||
public static CqlIdentifier cqlId(String identifier) {
|
||||
CqlIdentifier id = new CqlIdentifier(identifier);
|
||||
return id;
|
||||
}
|
||||
|
||||
public static CqlIdentifier quotedCqlId(String identifier) {
|
||||
CqlIdentifier id = new CqlIdentifier(identifier, true);
|
||||
return id;
|
||||
}
|
||||
|
||||
public static boolean isIdentifier(CharSequence chars) {
|
||||
return isUnquotedIdentifier(chars) || isQuotedIdentifier(chars);
|
||||
}
|
||||
|
||||
public static boolean isUnquotedIdentifier(CharSequence chars) {
|
||||
return UNQUOTED_IDENTIFIER_PATTERN.matcher(chars).matches();
|
||||
}
|
||||
|
||||
public static boolean isQuotedIdentifier(CharSequence chars) {
|
||||
return QUOTED_IDENTIFIER_PATTERN.matcher(chars).matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + (quoted ? 1231 : 1237);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
CqlIdentifier other = (CqlIdentifier) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (quoted != other.quoted)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ public class CqlStringUtils {
|
||||
|
||||
protected static final String SINGLE_QUOTE = "\'";
|
||||
protected static final String DOUBLE_SINGLE_QUOTE = "\'\'";
|
||||
protected static final String DOUBLE_QUOTE = "\"";
|
||||
public static final String DOUBLE_QUOTE = "\"";
|
||||
protected static final String DOUBLE_DOUBLE_QUOTE = "\"\"";
|
||||
protected static final String EMPTY_STRING = "";
|
||||
protected static final String TYPE_PARAMETER_PREFIX = "<";
|
||||
@@ -36,61 +36,6 @@ public class CqlStringUtils {
|
||||
public static final String UNESCAPED_DOUBLE_QUOTE_REGEX = "TODO";
|
||||
public static final Pattern UNESCAPED_DOUBLE_QUOTE_PATTERN = Pattern.compile(UNESCAPED_DOUBLE_QUOTE_REGEX);
|
||||
|
||||
public static final String UNQUOTED_IDENTIFIER_REGEX = "[a-zA-Z_][a-zA-Z0-9_]*";
|
||||
public static final Pattern UNQUOTED_IDENTIFIER_PATTERN = Pattern.compile(UNQUOTED_IDENTIFIER_REGEX);
|
||||
|
||||
public static boolean isUnquotedIdentifier(CharSequence chars) {
|
||||
return UNQUOTED_IDENTIFIER_PATTERN.matcher(chars).matches();
|
||||
}
|
||||
|
||||
public static void checkUnquotedIdentifier(CharSequence chars) {
|
||||
if (!CqlStringUtils.isUnquotedIdentifier(chars)) {
|
||||
throw new IllegalArgumentException("[" + chars + "] is not a valid CQL identifier");
|
||||
}
|
||||
}
|
||||
|
||||
public static final String QUOTED_IDENTIFIER_REGEX = "[a-zA-Z_]([a-zA-Z0-9_]|\"{2}+)*";
|
||||
public static final Pattern QUOTED_IDENTIFIER_PATTERN = Pattern.compile(QUOTED_IDENTIFIER_REGEX);
|
||||
|
||||
public static boolean isQuotedIdentifier(CharSequence chars) {
|
||||
return QUOTED_IDENTIFIER_PATTERN.matcher(chars).matches();
|
||||
}
|
||||
|
||||
public static void checkQuotedIdentifier(CharSequence chars) {
|
||||
if (!CqlStringUtils.isQuotedIdentifier(chars)) {
|
||||
throw new IllegalArgumentException("[" + chars + "] is not a valid CQL quoted identifier");
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isIdentifier(CharSequence chars) {
|
||||
return isUnquotedIdentifier(chars) || isQuotedIdentifier(chars);
|
||||
}
|
||||
|
||||
public static void checkIdentifier(CharSequence chars) {
|
||||
if (!CqlStringUtils.isIdentifier(chars)) {
|
||||
throw new IllegalArgumentException("[" + chars + "] is not a valid CQL quoted or unquoted identifier");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the given string as a legal Cassandra identifier.
|
||||
* <ul>
|
||||
* <li>If the given identifier is a legal unquoted identifier, it is returned unchanged.</li>
|
||||
* <li>If the given identifier is a legal quoted identifier, it is returned encased in double quotes.</li>
|
||||
* <li>If the given identifier is illegal, an {@link IllegalArgumentException} is thrown.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static String identifize(String candidate) {
|
||||
|
||||
checkIdentifier(candidate);
|
||||
|
||||
if (isUnquotedIdentifier(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
// else it must be quoted
|
||||
return doubleQuote(candidate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the given string as a legal Cassandra string column or table option value, by escaping single quotes and
|
||||
* encasing the result in single quotes. Given <code>null</code>, returns <code>null</code>.
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.cassandra.core.keyspace;
|
||||
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier;
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize;
|
||||
import org.springframework.cassandra.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Base class for column change specifications.
|
||||
@@ -25,22 +24,21 @@ import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize;
|
||||
*/
|
||||
public abstract class ColumnChangeSpecification {
|
||||
|
||||
private String name;
|
||||
private CqlIdentifier identifier;
|
||||
|
||||
public ColumnChangeSpecification(String name) {
|
||||
setName(name);
|
||||
}
|
||||
|
||||
private void setName(String name) {
|
||||
checkIdentifier(name);
|
||||
this.name = name;
|
||||
identifier = new CqlIdentifier(name);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return identifier.getName();
|
||||
}
|
||||
|
||||
public String getNameAsIdentifier() {
|
||||
return identifize(name);
|
||||
return identifier.toCql();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +15,14 @@
|
||||
*/
|
||||
package org.springframework.cassandra.core.keyspace;
|
||||
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier;
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize;
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.noNull;
|
||||
import static org.springframework.cassandra.core.PrimaryKeyType.PARTITIONED;
|
||||
import static org.springframework.cassandra.core.PrimaryKeyType.CLUSTERED;
|
||||
import static org.springframework.cassandra.core.Ordering.ASCENDING;
|
||||
import static org.springframework.cassandra.core.PrimaryKeyType.CLUSTERED;
|
||||
import static org.springframework.cassandra.core.PrimaryKeyType.PARTITIONED;
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.noNull;
|
||||
|
||||
import org.springframework.cassandra.core.PrimaryKeyType;
|
||||
import org.springframework.cassandra.core.CqlIdentifier;
|
||||
import org.springframework.cassandra.core.Ordering;
|
||||
import org.springframework.cassandra.core.PrimaryKeyType;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
|
||||
@@ -45,7 +44,7 @@ public class ColumnSpecification {
|
||||
*/
|
||||
public static final Ordering DEFAULT_ORDERING = ASCENDING;
|
||||
|
||||
private String name;
|
||||
private CqlIdentifier identifier;
|
||||
private DataType type; // TODO: determining if we should be coupling this to Datastax Java Driver type?
|
||||
private PrimaryKeyType keyType;
|
||||
private Ordering ordering;
|
||||
@@ -56,8 +55,7 @@ public class ColumnSpecification {
|
||||
* @return this
|
||||
*/
|
||||
public ColumnSpecification name(String name) {
|
||||
checkIdentifier(name);
|
||||
this.name = name;
|
||||
identifier = new CqlIdentifier(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -148,11 +146,11 @@ public class ColumnSpecification {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return identifier.getName();
|
||||
}
|
||||
|
||||
public String getNameAsIdentifier() {
|
||||
return identifize(name);
|
||||
return identifier.toCql();
|
||||
}
|
||||
|
||||
public DataType getType() {
|
||||
@@ -172,7 +170,7 @@ public class ColumnSpecification {
|
||||
}
|
||||
|
||||
public StringBuilder toCql(StringBuilder cql) {
|
||||
return (cql = noNull(cql)).append(name).append(" ").append(type);
|
||||
return (cql = noNull(cql)).append(identifier).append(" ").append(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package org.springframework.cassandra.core.keyspace;
|
||||
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier;
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize;
|
||||
|
||||
import org.springframework.cassandra.core.CqlIdentifier;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -31,7 +29,7 @@ public class CreateIndexSpecification extends IndexNameSpecification<CreateIndex
|
||||
|
||||
private boolean ifNotExists = false;
|
||||
private boolean custom = false;
|
||||
private String tableName;
|
||||
private CqlIdentifier identifier;
|
||||
private String columnName;
|
||||
private String using;
|
||||
|
||||
@@ -89,17 +87,16 @@ public class CreateIndexSpecification extends IndexNameSpecification<CreateIndex
|
||||
* @return this
|
||||
*/
|
||||
public CreateIndexSpecification tableName(String tableName) {
|
||||
checkIdentifier(tableName);
|
||||
this.tableName = tableName;
|
||||
identifier = new CqlIdentifier(tableName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
return identifier.getName();
|
||||
}
|
||||
|
||||
public String getTableNameAsIdentifier() {
|
||||
return identifize(tableName);
|
||||
return identifier.toCql();
|
||||
}
|
||||
|
||||
public CreateIndexSpecification columnName(String columnName) {
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.cassandra.core.keyspace;
|
||||
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier;
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize;
|
||||
import org.springframework.cassandra.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Abstract builder class to support the construction of table specifications.
|
||||
@@ -29,7 +28,7 @@ public abstract class IndexNameSpecification<T extends IndexNameSpecification<T>
|
||||
/**
|
||||
* The name of the index.
|
||||
*/
|
||||
private String name;
|
||||
private CqlIdentifier identifier;
|
||||
|
||||
/**
|
||||
* Sets the index name.
|
||||
@@ -38,17 +37,16 @@ public abstract class IndexNameSpecification<T extends IndexNameSpecification<T>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T name(String name) {
|
||||
checkIdentifier(name);
|
||||
this.name = name;
|
||||
identifier = new CqlIdentifier(name);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return identifier.getName();
|
||||
}
|
||||
|
||||
public String getNameAsIdentifier() {
|
||||
return identifize(name);
|
||||
return identifier.toCql();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.springframework.cassandra.core.keyspace;
|
||||
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier;
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize;
|
||||
import org.springframework.cassandra.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Abstract builder class to support the construction of keyspace specifications.
|
||||
@@ -13,9 +12,9 @@ import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize;
|
||||
public abstract class KeyspaceActionSpecification<T extends KeyspaceActionSpecification<T>> {
|
||||
|
||||
/**
|
||||
* The name of the table.
|
||||
* The name of the keyspace.
|
||||
*/
|
||||
private String name;
|
||||
private CqlIdentifier identifier;
|
||||
|
||||
/**
|
||||
* Sets the keyspace name.
|
||||
@@ -24,17 +23,16 @@ public abstract class KeyspaceActionSpecification<T extends KeyspaceActionSpecif
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T name(String name) {
|
||||
checkIdentifier(name);
|
||||
this.name = name;
|
||||
identifier = new CqlIdentifier(name);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return identifier.getName();
|
||||
}
|
||||
|
||||
public String getNameAsIdentifier() {
|
||||
return identifize(name);
|
||||
return identifier.toCql();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +41,7 @@ public abstract class KeyspaceActionSpecification<T extends KeyspaceActionSpecif
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Keyspace Action Specification {name: " + name + ", class: " + this.getClass() + "}");
|
||||
sb.append("Keyspace Action Specification {name: " + identifier + ", class: " + this.getClass() + "}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -65,12 +63,12 @@ public abstract class KeyspaceActionSpecification<T extends KeyspaceActionSpecif
|
||||
return false;
|
||||
}
|
||||
KeyspaceActionSpecification<?> thatSpec = (KeyspaceActionSpecification<?>) that;
|
||||
return this.name.equals(thatSpec.name) && this.getClass().equals(that.getClass());
|
||||
return this.identifier.equals(thatSpec.identifier) && this.getClass().equals(that.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.name.hashCode() ^ this.getClass().hashCode();
|
||||
return this.identifier.hashCode() ^ this.getClass().hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.cassandra.core.keyspace;
|
||||
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.checkIdentifier;
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.identifize;
|
||||
import org.springframework.cassandra.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Abstract builder class to support the construction of table specifications.
|
||||
@@ -29,7 +28,7 @@ public abstract class TableNameSpecification<T extends TableNameSpecification<T>
|
||||
/**
|
||||
* The name of the table.
|
||||
*/
|
||||
private String name;
|
||||
private CqlIdentifier identifier;
|
||||
|
||||
/**
|
||||
* Sets the table name.
|
||||
@@ -38,16 +37,15 @@ public abstract class TableNameSpecification<T extends TableNameSpecification<T>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T name(String name) {
|
||||
checkIdentifier(name);
|
||||
this.name = name;
|
||||
identifier = new CqlIdentifier(name);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return identifier.getName();
|
||||
}
|
||||
|
||||
public String getNameAsIdentifier() {
|
||||
return identifize(name);
|
||||
return identifier.toCql();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.springframework.cassandra.test.unit.core.cql;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.cassandra.core.CqlIdentifier.isQuotedIdentifier;
|
||||
import static org.springframework.cassandra.core.CqlIdentifier.isUnquotedIdentifier;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class CqlIdentifierTest {
|
||||
|
||||
@Test
|
||||
public void testIsQuotedIdentifier() throws Exception {
|
||||
assertFalse(isQuotedIdentifier("my\"id"));
|
||||
assertTrue(isQuotedIdentifier("my\"\"id"));
|
||||
assertFalse(isUnquotedIdentifier("my\"id"));
|
||||
assertTrue(isUnquotedIdentifier("myid"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +1,5 @@
|
||||
package org.springframework.cassandra.test.unit.core.cql;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.isQuotedIdentifier;
|
||||
import static org.springframework.cassandra.core.cql.CqlStringUtils.isUnquotedIdentifier;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class CqlStringUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testIsQuotedIdentifier() throws Exception {
|
||||
assertFalse(isQuotedIdentifier("my\"id"));
|
||||
assertTrue(isQuotedIdentifier("my\"\"id"));
|
||||
assertFalse(isUnquotedIdentifier("my\"id"));
|
||||
assertTrue(isUnquotedIdentifier("myid"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public class AlterTableCqlGeneratorTests {
|
||||
* Asserts that the preamble is first & correctly formatted in the given CQL string.
|
||||
*/
|
||||
public static void assertPreamble(String tableName, String cql) {
|
||||
System.out.println("cql: " + cql);
|
||||
assertTrue(cql.startsWith("ALTER TABLE " + tableName + " "));
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Class<?>></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 };
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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<Class<?>></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
|
||||
|
||||
@@ -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 <cluster> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 <mapping> 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);
|
||||
}
|
||||
}
|
||||
@@ -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 <converter> 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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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() };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.cassandraunit.utils.EmbeddedCassandraServerHelper;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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> {
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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() };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,8 +67,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() };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user