DATACASS-656 - Migrate to Cassandra driver 4.
Original pull request: #167.
This commit is contained in:
13
pom.xml
13
pom.xml
@@ -85,12 +85,13 @@
|
||||
<properties>
|
||||
<build.cassandra.host>localhost</build.cassandra.host>
|
||||
<build.cassandra.mode>embedded</build.cassandra.mode>
|
||||
<build.cassandra.native_transport_port>19042</build.cassandra.native_transport_port>
|
||||
<build.cassandra.native_transport_port>19042
|
||||
</build.cassandra.native_transport_port>
|
||||
<build.cassandra.rpc_port>19160</build.cassandra.rpc_port>
|
||||
<build.cassandra.ssl_storage_port>17001</build.cassandra.ssl_storage_port>
|
||||
<build.cassandra.storage_port>17000</build.cassandra.storage_port>
|
||||
<cassandra.version>3.11.4</cassandra.version>
|
||||
<cassandra-driver.version>3.7.2</cassandra-driver.version>
|
||||
<cassandra-driver.version>4.3.0</cassandra-driver.version>
|
||||
<dist.id>spring-data-cassandra</dist.id>
|
||||
<el.version>1.0</el.version>
|
||||
<multithreadedtc.version>1.01</multithreadedtc.version>
|
||||
@@ -117,15 +118,15 @@
|
||||
|
||||
<!-- Cassandra Driver -->
|
||||
<dependency>
|
||||
<groupId>com.datastax.cassandra</groupId>
|
||||
<artifactId>cassandra-driver-core</artifactId>
|
||||
<groupId>com.datastax.oss</groupId>
|
||||
<artifactId>java-driver-core</artifactId>
|
||||
<version>${cassandra-driver.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.datastax.oss</groupId>
|
||||
<artifactId>java-driver-core</artifactId>
|
||||
<version>4.2.0</version>
|
||||
<artifactId>java-driver-query-builder</artifactId>
|
||||
<version>${cassandra-driver.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- CDI -->
|
||||
|
||||
@@ -75,13 +75,13 @@
|
||||
|
||||
<!-- Cassandra driver -->
|
||||
<dependency>
|
||||
<groupId>com.datastax.cassandra</groupId>
|
||||
<artifactId>cassandra-driver-core</artifactId>
|
||||
<groupId>com.datastax.oss</groupId>
|
||||
<artifactId>java-driver-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.datastax.oss</groupId>
|
||||
<artifactId>java-driver-core</artifactId>
|
||||
<artifactId>java-driver-query-builder</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Reactor -->
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import org.springframework.dao.PermissionDeniedDataAccessException;
|
||||
|
||||
import com.datastax.oss.driver.api.core.metadata.EndPoint;
|
||||
|
||||
/**
|
||||
* Spring data access exception for a Cassandra authentication failure.
|
||||
*
|
||||
@@ -28,14 +28,14 @@ public class CassandraAuthenticationException extends PermissionDeniedDataAccess
|
||||
|
||||
private static final long serialVersionUID = 8556304586797273927L;
|
||||
|
||||
private InetAddress host;
|
||||
private EndPoint host;
|
||||
|
||||
public CassandraAuthenticationException(InetAddress host, String msg, Throwable cause) {
|
||||
public CassandraAuthenticationException(EndPoint host, String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public InetAddress getHost() {
|
||||
public EndPoint getHost() {
|
||||
return host;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
|
||||
import com.datastax.oss.driver.api.core.metadata.Node;
|
||||
|
||||
/**
|
||||
* Spring data access exception for Cassandra when no host is available.
|
||||
*
|
||||
@@ -31,14 +32,14 @@ public class CassandraConnectionFailureException extends DataAccessResourceFailu
|
||||
|
||||
private static final long serialVersionUID = 6299912054261646552L;
|
||||
|
||||
private final Map<InetSocketAddress, Throwable> messagesByHost = new HashMap<>();
|
||||
private final Map<Node, Throwable> messagesByHost = new HashMap<>();
|
||||
|
||||
public CassandraConnectionFailureException(Map<InetSocketAddress, Throwable> map, String msg, Throwable cause) {
|
||||
public CassandraConnectionFailureException(Map<Node, Throwable> map, String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
this.messagesByHost.putAll(map);
|
||||
}
|
||||
|
||||
public Map<InetSocketAddress, Throwable> getMessagesByHost() {
|
||||
public Map<Node, Throwable> getMessagesByHost() {
|
||||
return Collections.unmodifiableMap(messagesByHost);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ public class CassandraReadTimeoutException extends QueryTimeoutException {
|
||||
this.wasDataReceived = wasDataReceived;
|
||||
}
|
||||
|
||||
// TODO: Rename wasDataPresent
|
||||
public boolean getWasDataReceived() {
|
||||
return wasDataReceived;
|
||||
}
|
||||
|
||||
@@ -16,16 +16,19 @@
|
||||
package org.springframework.data.cassandra;
|
||||
|
||||
import org.springframework.dao.NonTransientDataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Spring data access exception for when Cassandra schema element being created already exists.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class CassandraSchemaElementExistsException extends NonTransientDataAccessException {
|
||||
|
||||
private static final long serialVersionUID = 7798361273692300162L;
|
||||
|
||||
@Deprecated
|
||||
public enum ElementType {
|
||||
KEYSPACE, TABLE, COLUMN, INDEX
|
||||
}
|
||||
@@ -33,6 +36,7 @@ public class CassandraSchemaElementExistsException extends NonTransientDataAcces
|
||||
private String elementName;
|
||||
private ElementType elementType;
|
||||
|
||||
@Deprecated
|
||||
public CassandraSchemaElementExistsException(String elementName, ElementType elementType, String msg,
|
||||
Throwable cause) {
|
||||
super(msg, cause);
|
||||
@@ -40,10 +44,18 @@ public class CassandraSchemaElementExistsException extends NonTransientDataAcces
|
||||
this.elementType = elementType;
|
||||
}
|
||||
|
||||
public CassandraSchemaElementExistsException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public String getElementName() {
|
||||
return elementName;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public ElementType getElementType() {
|
||||
return elementType;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.datastax.driver.core.ColumnDefinitions;
|
||||
import com.datastax.driver.core.ExecutionInfo;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.ColumnDefinitions;
|
||||
import com.datastax.oss.driver.api.core.cql.ExecutionInfo;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
|
||||
/**
|
||||
* The reactive result of a query.
|
||||
@@ -29,13 +29,12 @@ import com.datastax.driver.core.Row;
|
||||
* The retrieval of the rows of a {@link ReactiveResultSet} is generally paged (a first page of result is fetched and
|
||||
* the next one is only fetched once all the results of the first one has been consumed). The size of the pages can be
|
||||
* configured either globally through {@link com.datastax.driver.core.QueryOptions#setFetchSize} or per-statement with
|
||||
* {@link com.datastax.driver.core.Statement#setFetchSize}.
|
||||
* {@link com.datastax.oss.driver.api.core.cql.Statement#setFetchSize}.
|
||||
* <p>
|
||||
* Please note however that this {@link ReactiveResultSet} paging is not available with the version 1 of the native
|
||||
* protocol (i.e. with Cassandra 1.2 or if version 1 has been explicitly requested through
|
||||
* {@link com.datastax.driver.core.Cluster.Builder#withProtocolVersion}). If the protocol version 1 is in use, a
|
||||
* {@link ReactiveResultSet} is always fetched in it's entirely and it's up to the client to make sure that no query can
|
||||
* yield {@link ReactiveResultSet} that won't hold in memory.
|
||||
* protocol (i.e. with Cassandra 1.2 or if version 1 has been explicitly requested). If the protocol version 1 is in
|
||||
* use, a {@link ReactiveResultSet} is always fetched in it's entirely and it's up to the client to make sure that no
|
||||
* query can yield {@link ReactiveResultSet} that won't hold in memory.
|
||||
* <p>
|
||||
* Note that this class is not thread-safe.
|
||||
*
|
||||
@@ -51,8 +50,8 @@ public interface ReactiveResultSet {
|
||||
* Returns a {@link Flux} over the rows contained in this result set applying transparent paging.
|
||||
* <p>
|
||||
* The {@link Flux} will stream over all records that in this {@link ReactiveResultSet} according to the reactive
|
||||
* demand and fetch next result chunks by issuing the underlying query with the current
|
||||
* {@link com.datastax.driver.core.PagingState} applied.
|
||||
* demand and fetch next result chunks by issuing the underlying query with the current {@link java.nio.ByteBuffer
|
||||
* paging state} applied.
|
||||
* <p>
|
||||
*
|
||||
* @return a {@link Flux} of rows that will stream over all {@link Row rows} of the entire result.
|
||||
@@ -61,8 +60,8 @@ public interface ReactiveResultSet {
|
||||
|
||||
/**
|
||||
* Returns a {@link Flux} over the rows contained in this result set chunk. This method does not apply transparent
|
||||
* paging. Use {@link com.datastax.driver.core.PagingState} from {@link #getExecutionInfo()} to issue subsequent
|
||||
* queries to obtain the next result chunk.
|
||||
* paging. Use {@link java.nio.ByteBuffer paging state} from {@link #getExecutionInfo()} to issue subsequent queries
|
||||
* to obtain the next result chunk.
|
||||
*
|
||||
* @return a {@link Flux} of rows that will stream over all {@link Row rows} in this {@link ReactiveResultSet}.
|
||||
* @since 2.1
|
||||
|
||||
@@ -20,14 +20,11 @@ import reactor.core.publisher.Mono;
|
||||
import java.io.Closeable;
|
||||
import java.util.Map;
|
||||
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.RegularStatement;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.exceptions.NoHostAvailableException;
|
||||
import com.datastax.driver.core.exceptions.QueryExecutionException;
|
||||
import com.datastax.driver.core.exceptions.QueryValidationException;
|
||||
import com.datastax.driver.core.exceptions.UnsupportedFeatureException;
|
||||
import com.datastax.oss.driver.api.core.context.DriverContext;
|
||||
import com.datastax.oss.driver.api.core.cql.BoundStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
|
||||
/**
|
||||
* A session holds connections to a Cassandra cluster, allowing it to be queried. {@link ReactiveSession} executes
|
||||
@@ -65,11 +62,11 @@ public interface ReactiveSession extends Closeable {
|
||||
boolean isClosed();
|
||||
|
||||
/**
|
||||
* Returns the {@code Cluster} object this session is part of.
|
||||
* Returns a context that provides access to all the policies used by this driver instance.
|
||||
*
|
||||
* @return the {@code Cluster} object this session is part of.
|
||||
* @return a context that provides access to all the policies used by this driver instance.
|
||||
*/
|
||||
Cluster getCluster();
|
||||
DriverContext getContext();
|
||||
|
||||
/**
|
||||
* Executes the provided query.
|
||||
@@ -79,11 +76,6 @@ public interface ReactiveSession extends Closeable {
|
||||
* @param query the CQL query to execute.
|
||||
* @return the result of the query. That result will never be null but can be empty (and will be for any non SELECT
|
||||
* query).
|
||||
* @throws NoHostAvailableException if no host in the cluster can be contacted successfully to execute this query.
|
||||
* @throws QueryExecutionException if the query triggered an execution exception, i.e. an exception thrown by
|
||||
* Cassandra when it cannot execute the query with the requested consistency level successfully.
|
||||
* @throws QueryValidationException if the query if invalid (syntax error, unauthorized or any other validation
|
||||
* problem).
|
||||
*/
|
||||
Mono<ReactiveResultSet> execute(String query);
|
||||
|
||||
@@ -94,16 +86,9 @@ public interface ReactiveSession extends Closeable {
|
||||
*
|
||||
* @param query the CQL query to execute.
|
||||
* @param values values required for the execution of {@code query}. See
|
||||
* {@link SimpleStatement#SimpleStatement(String, Object...)} for more details.
|
||||
* {@link SimpleStatement#newInstance(String, Object...)} for more details.
|
||||
* @return the result of the query. That result will never be null but can be empty (and will be for any non SELECT
|
||||
* query).
|
||||
* @throws NoHostAvailableException if no host in the cluster can be contacted successfully to execute this query.
|
||||
* @throws QueryExecutionException if the query triggered an execution exception, i.e. an exception thrown by
|
||||
* Cassandra when it cannot execute the query with the requested consistency level successfully.
|
||||
* @throws QueryValidationException if the query if invalid (syntax error, unauthorized or any other validation
|
||||
* problem).
|
||||
* @throws UnsupportedFeatureException if version 1 of the protocol is in use (i.e. if you've forced version 1 through
|
||||
* {@link Cluster.Builder#withProtocolVersion} or you use Cassandra 1.2).
|
||||
*/
|
||||
Mono<ReactiveResultSet> execute(String query, Object... values);
|
||||
|
||||
@@ -114,16 +99,9 @@ public interface ReactiveSession extends Closeable {
|
||||
*
|
||||
* @param query the CQL query to execute.
|
||||
* @param values values required for the execution of {@code query}. See
|
||||
* {@link SimpleStatement#SimpleStatement(String, Map)} for more details.
|
||||
* {@link SimpleStatement#newInstance(String, Map)} for more details.
|
||||
* @return the result of the query. That result will never be null but can be empty (and will be for any non SELECT
|
||||
* query).
|
||||
* @throws NoHostAvailableException if no host in the cluster can be contacted successfully to execute this query.
|
||||
* @throws QueryExecutionException if the query triggered an execution exception, i.e. an exception thrown by
|
||||
* Cassandra when it cannot execute the query with the requested consistency level successfully.
|
||||
* @throws QueryValidationException if the query if invalid (syntax error, unauthorized or any other validation
|
||||
* problem).
|
||||
* @throws UnsupportedFeatureException if version 1 or 2 of the protocol is in use (i.e. if you've forced it through
|
||||
* {@link Cluster.Builder#withProtocolVersion} or you use Cassandra 1.2 or 2.0).
|
||||
*/
|
||||
Mono<ReactiveResultSet> execute(String query, Map<String, Object> values);
|
||||
|
||||
@@ -138,23 +116,14 @@ public interface ReactiveSession extends Closeable {
|
||||
* @param statement the CQL query to execute (that can be any {@link Statement}).
|
||||
* @return the result of the query. That result will never be null but can be empty (and will be for any non SELECT
|
||||
* query).
|
||||
* @throws NoHostAvailableException if no host in the cluster can be contacted successfully to execute this query.
|
||||
* @throws QueryExecutionException if the query triggered an execution exception, i.e. an exception thrown by
|
||||
* Cassandra when it cannot execute the query with the requested consistency level successfully.
|
||||
* @throws QueryValidationException if the query if invalid (syntax error, unauthorized or any other validation
|
||||
* problem).
|
||||
* @throws UnsupportedFeatureException if the protocol version 1 is in use and a feature not supported has been used.
|
||||
* Features that are not supported by the version protocol 1 include: BatchStatement, ReactiveResultSet
|
||||
* paging and binary values in RegularStatement.
|
||||
*/
|
||||
Mono<ReactiveResultSet> execute(Statement statement);
|
||||
Mono<ReactiveResultSet> execute(Statement<?> statement);
|
||||
|
||||
/**
|
||||
* Prepares the provided query string.
|
||||
*
|
||||
* @param query the CQL query string to prepare
|
||||
* @return the prepared statement corresponding to {@code query}.
|
||||
* @throws NoHostAvailableException if no host in the cluster can be contacted successfully to prepare this query.
|
||||
*/
|
||||
Mono<PreparedStatement> prepare(String query);
|
||||
|
||||
@@ -165,7 +134,7 @@ public interface ReactiveSession extends Closeable {
|
||||
* inherit the query properties set on {@code statement}. Concretely, this means that in the following code:
|
||||
*
|
||||
* <pre>
|
||||
* RegularStatement toPrepare = new SimpleStatement("SELECT * FROM test WHERE k=?")
|
||||
* Statement toPrepare = SimpleStatement.newInstance("SELECT * FROM test WHERE k=?")
|
||||
* .setConsistencyLevel(ConsistencyLevel.QUORUM);
|
||||
* PreparedStatement prepared = session.prepare(toPrepare);
|
||||
* session.execute(prepared.bind("someValue"));
|
||||
@@ -179,21 +148,14 @@ public interface ReactiveSession extends Closeable {
|
||||
*
|
||||
* @param statement the statement to prepare
|
||||
* @return the prepared statement corresponding to {@code statement}.
|
||||
* @throws NoHostAvailableException if no host in the cluster can be contacted successfully to prepare this statement.
|
||||
* @throws IllegalArgumentException if {@code statement.getValues() != null} (values for executing a prepared
|
||||
* statement should be provided after preparation though the {@link PreparedStatement#bind} method or
|
||||
* through a corresponding {@link BoundStatement}).
|
||||
*/
|
||||
Mono<PreparedStatement> prepare(RegularStatement statement);
|
||||
Mono<PreparedStatement> prepare(SimpleStatement statement);
|
||||
|
||||
/**
|
||||
* Initiates a shutdown of this session instance and blocks until that shutdown completes.
|
||||
* <p/>
|
||||
* This method is a shortcut for {@code closeAsync().get()}.
|
||||
* <p/>
|
||||
* Note that this method does not close the corresponding {@code Cluster} instance (which holds additional resources,
|
||||
* in particular internal executors that must be shut down in order for the client program to terminate). If you want
|
||||
* to do so, use {@link Cluster#close}, but note that it will close all sessions created from that cluster.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
|
||||
@@ -15,18 +15,17 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
|
||||
/**
|
||||
* A factory for Apache Cassandra sessions.
|
||||
* <p>
|
||||
* An alternative to the {@link com.datastax.driver.core.Cluster} facility, a {@link SessionFactory} object is the
|
||||
* preferred means of getting a connection. The {@link SessionFactory} interface is implemented by a {@link Session}
|
||||
* provider.
|
||||
* A {@link SessionFactory} object is the preferred means of getting a connection. The {@link SessionFactory} interface
|
||||
* is implemented by a {@link CqlSession} provider.
|
||||
* <p>
|
||||
* A {@link SessionFactory} object can have properties that can be modified when necessary. For example, if the
|
||||
* {@link Session} is moved to a different server, the property for the server can be changed. The benefit is that
|
||||
* {@link CqlSession} is moved to a different server, the property for the server can be changed. The benefit is that
|
||||
* because the data source's properties can be changed, any code accessing that {@link SessionFactory} does not need to
|
||||
* be changed.
|
||||
*
|
||||
@@ -37,23 +36,11 @@ import com.datastax.oss.driver.api.core.CqlSession;
|
||||
public interface SessionFactory {
|
||||
|
||||
/**
|
||||
* Attempts to establish a {@link Session} with the connection infrastructure that this {@link SessionFactory} object
|
||||
* represents.
|
||||
* Attempts to establish a {@link CqlSession} with the connection infrastructure that this {@link SessionFactory}
|
||||
* object represents.
|
||||
*
|
||||
* @return a {@link Session} to Apache Cassandra.
|
||||
* @return a {@link CqlSession} to Apache Cassandra.
|
||||
*/
|
||||
Session getSession();
|
||||
|
||||
/**
|
||||
* Attempts to establish a {@link Session} with the connection infrastructure that this {@link SessionFactory} object
|
||||
* represents.
|
||||
*
|
||||
* @return a {@link Session} to Apache Cassandra.
|
||||
*/
|
||||
default CqlSession getCqlSession() {
|
||||
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
CqlSession getSession();
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,10 @@ import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
@@ -28,7 +31,7 @@ import org.springframework.data.cassandra.core.CassandraAdminTemplate;
|
||||
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;
|
||||
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory;
|
||||
import org.springframework.data.cassandra.core.cql.session.init.KeyspacePopulator;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||
import org.springframework.data.cassandra.core.mapping.SimpleTupleTypeFactory;
|
||||
import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;
|
||||
@@ -39,8 +42,8 @@ import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
|
||||
/**
|
||||
* Base class for Spring Data Cassandra configuration using JavaConfig.
|
||||
@@ -51,91 +54,72 @@ import com.datastax.driver.core.Session;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Configuration
|
||||
public abstract class AbstractCassandraConfiguration extends AbstractClusterConfiguration
|
||||
implements BeanClassLoaderAware {
|
||||
public abstract class AbstractCassandraConfiguration extends AbstractSessionConfiguration
|
||||
implements BeanClassLoaderAware, BeanFactoryAware {
|
||||
|
||||
private @Nullable ClassLoader beanClassLoader;
|
||||
private @Nullable BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Returns the initialized {@link Session} instance.
|
||||
* Returns the initialized {@link CqlSession} instance.
|
||||
*
|
||||
* @return the {@link Session}.
|
||||
* @return the {@link CqlSession}.
|
||||
* @throws IllegalStateException if the session factory is not initialized.
|
||||
*/
|
||||
protected Session getRequiredSession() {
|
||||
protected SessionFactory getRequiredSessionFactory() {
|
||||
|
||||
CassandraSessionFactoryBean factoryBean = session();
|
||||
Assert.state(beanFactory != null, "BeanFactory not initialized");
|
||||
|
||||
Session session = factoryBean.getObject();
|
||||
|
||||
Assert.state(session != null, "Session factory not initialized");
|
||||
|
||||
return session;
|
||||
return beanFactory.getBean(SessionFactory.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link CassandraSessionFactoryBean} that provides a Cassandra {@link com.datastax.driver.core.Session}.
|
||||
* The lifecycle of {@link CassandraSessionFactoryBean} initializes the {@link #getSchemaAction() schema} in the
|
||||
* Creates a {@link SessionFactoryFactoryBean} that provides a {@link SessionFactory}. The lifecycle of
|
||||
* {@link SessionFactoryFactoryBean} initializes the {@link #getSchemaAction() schema} in the
|
||||
* {@link #getKeyspaceName() configured keyspace}.
|
||||
*
|
||||
* @return the {@link CassandraSessionFactoryBean}.
|
||||
* @see #cluster()
|
||||
* @return the {@link SessionFactoryFactoryBean}.
|
||||
* @see #cassandraConverter()
|
||||
* @see #getKeyspaceName()
|
||||
* @see #getSchemaAction()
|
||||
* @see #getStartupScripts()
|
||||
* @see #getShutdownScripts()
|
||||
* @see #keyspacePopulator()
|
||||
* @see #keyspaceCleaner()
|
||||
*/
|
||||
@Bean
|
||||
public CassandraSessionFactoryBean session() {
|
||||
public SessionFactoryFactoryBean sessionFactory(CqlSession cqlSession) {
|
||||
|
||||
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
|
||||
SessionFactoryFactoryBean bean = new SessionFactoryFactoryBean();
|
||||
|
||||
session.setCluster(getRequiredCluster());
|
||||
session.setConverter(cassandraConverter());
|
||||
session.setKeyspaceName(getKeyspaceName());
|
||||
session.setSchemaAction(getSchemaAction());
|
||||
session.setStartupScripts(getStartupScripts());
|
||||
session.setShutdownScripts(getShutdownScripts());
|
||||
bean.setSession(cqlSession);
|
||||
|
||||
return session;
|
||||
bean.setConverter(beanFactory.getBean(CassandraConverter.class));
|
||||
bean.setSchemaAction(getSchemaAction());
|
||||
bean.setKeyspacePopulator(keyspacePopulator());
|
||||
bean.setKeyspacePopulator(keyspaceCleaner());
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link CassandraCqlSessionFactoryBean} that provides a Cassandra
|
||||
* {@link com.datastax.oss.driver.api.core.CqlSession}. The lifecycle of {@link CassandraSessionFactoryBean}
|
||||
* initializes the {@link #getSchemaAction() schema} in the {@link #getKeyspaceName() configured keyspace}.
|
||||
* Creates a {@link KeyspacePopulator} to initialize the keyspace.
|
||||
*
|
||||
* @return the {@link CassandraSessionFactoryBean}.
|
||||
* @see #cluster()
|
||||
* @see #cassandraConverter()
|
||||
* @see #getKeyspaceName()
|
||||
* @see #getSchemaAction()
|
||||
* @see #getStartupScripts()
|
||||
* @see #getShutdownScripts()
|
||||
* @return the {@link KeyspacePopulator} or {@code null} if none configured.
|
||||
* @see org.springframework.data.cassandra.core.cql.session.init.ResourceKeyspacePopulator
|
||||
*/
|
||||
@Bean
|
||||
public CqlSessionFactoryBean cassandraSession() {
|
||||
|
||||
CqlSessionFactoryBean session = new CqlSessionFactoryBean();
|
||||
|
||||
session.setContactPoints(getContactPoints());
|
||||
session.setPort(getPort());
|
||||
session.setKeyspaceName(getKeyspaceName());
|
||||
|
||||
return session;
|
||||
@Nullable
|
||||
protected KeyspacePopulator keyspacePopulator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link DefaultSessionFactory} using the configured {@link #session()} to be used with
|
||||
* {@link org.springframework.data.cassandra.core.CassandraTemplate}.
|
||||
* Creates a {@link KeyspacePopulator} to cleanup the keyspace.
|
||||
*
|
||||
* @return {@link SessionFactory} used to initialize the Template API.
|
||||
* @since 2.0
|
||||
* @return the {@link KeyspacePopulator} or {@code null} if none configured.
|
||||
* @see org.springframework.data.cassandra.core.cql.session.init.ResourceKeyspacePopulator
|
||||
*/
|
||||
@Bean
|
||||
public SessionFactory sessionFactory() {
|
||||
return new DefaultSessionFactory(getRequiredSession());
|
||||
@Nullable
|
||||
protected KeyspacePopulator keyspaceCleaner() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,15 +133,12 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
|
||||
@Bean
|
||||
public CassandraConverter cassandraConverter() {
|
||||
|
||||
try {
|
||||
MappingCassandraConverter mappingCassandraConverter = new MappingCassandraConverter(cassandraMapping());
|
||||
MappingCassandraConverter mappingCassandraConverter = new MappingCassandraConverter(
|
||||
beanFactory.getBean(CassandraMappingContext.class));
|
||||
|
||||
mappingCassandraConverter.setCustomConversions(customConversions());
|
||||
mappingCassandraConverter.setCustomConversions(beanFactory.getBean(CassandraCustomConversions.class));
|
||||
|
||||
return mappingCassandraConverter;
|
||||
} catch (ClassNotFoundException cause) {
|
||||
throw new IllegalStateException(cause);
|
||||
}
|
||||
return mappingCassandraConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,22 +151,21 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
|
||||
@Bean
|
||||
public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
|
||||
|
||||
Cluster cluster = getRequiredCluster();
|
||||
|
||||
UserTypeResolver userTypeResolver = new SimpleUserTypeResolver(cluster, getKeyspaceName());
|
||||
UserTypeResolver userTypeResolver = new SimpleUserTypeResolver(getRequiredSession(),
|
||||
CqlIdentifier.fromCql(getKeyspaceName()));
|
||||
|
||||
CassandraMappingContext mappingContext = new CassandraMappingContext(userTypeResolver,
|
||||
new SimpleTupleTypeFactory(cluster));
|
||||
SimpleTupleTypeFactory.DEFAULT);
|
||||
|
||||
Optional.ofNullable(this.beanClassLoader).ifPresent(mappingContext::setBeanClassLoader);
|
||||
|
||||
mappingContext.setInitialEntitySet(getInitialEntitySet());
|
||||
|
||||
CustomConversions customConversions = customConversions();
|
||||
CustomConversions customConversions = beanFactory.getBean(CassandraCustomConversions.class);
|
||||
|
||||
mappingContext.setCustomConversions(customConversions);
|
||||
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
|
||||
mappingContext.setCodecRegistry(cluster.getConfiguration().getCodecRegistry());
|
||||
mappingContext.setCodecRegistry(getRequiredSession().getContext().getCodecRegistry());
|
||||
|
||||
return mappingContext;
|
||||
}
|
||||
@@ -225,7 +205,7 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
|
||||
*/
|
||||
@Bean
|
||||
public CassandraAdminTemplate cassandraTemplate() throws Exception {
|
||||
return new CassandraAdminTemplate(sessionFactory(), cassandraConverter());
|
||||
return new CassandraAdminTemplate(getRequiredSessionFactory(), beanFactory.getBean(CassandraConverter.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -233,6 +213,11 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()}. This method must never return {@literal null}.
|
||||
@@ -241,13 +226,6 @@ public abstract class AbstractCassandraConfiguration extends AbstractClusterConf
|
||||
return new String[] { getClass().getPackage().getName() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the keyspace to connect to.
|
||||
*
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
protected abstract String getKeyspaceName();
|
||||
|
||||
/**
|
||||
* The {@link SchemaAction} to perform at startup. Defaults to {@link SchemaAction#NONE}.
|
||||
*/
|
||||
|
||||
@@ -1,351 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.DropKeyspaceSpecification;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.AuthProvider;
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.NettyOptions;
|
||||
import com.datastax.driver.core.PoolingOptions;
|
||||
import com.datastax.driver.core.ProtocolVersion;
|
||||
import com.datastax.driver.core.QueryOptions;
|
||||
import com.datastax.driver.core.SocketOptions;
|
||||
import com.datastax.driver.core.TimestampGenerator;
|
||||
import com.datastax.driver.core.policies.AddressTranslator;
|
||||
import com.datastax.driver.core.policies.LoadBalancingPolicy;
|
||||
import com.datastax.driver.core.policies.ReconnectionPolicy;
|
||||
import com.datastax.driver.core.policies.RetryPolicy;
|
||||
import com.datastax.driver.core.policies.SpeculativeExecutionPolicy;
|
||||
|
||||
/**
|
||||
* Base class for Spring Cassandra configuration that can handle creating namespaces, execute arbitrary CQL on startup &
|
||||
* shutdown, and optionally drop keyspaces.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Jorge Davison
|
||||
* @author Mark Paluch
|
||||
* @author John Blum
|
||||
*/
|
||||
@Configuration
|
||||
public abstract class AbstractClusterConfiguration {
|
||||
|
||||
/**
|
||||
* Returns the initialized {@link Cluster} instance.
|
||||
*
|
||||
* @return the {@link Cluster}.
|
||||
* @throws IllegalStateException if the cluster factory is not initialized.
|
||||
*/
|
||||
protected Cluster getRequiredCluster() {
|
||||
|
||||
CassandraClusterFactoryBean factoryBean = cluster();
|
||||
|
||||
Cluster cluster = factoryBean.getObject();
|
||||
|
||||
Assert.state(cluster != null, "Cluster not initialized");
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link CassandraClusterFactoryBean} that provides a Cassandra {@link com.datastax.driver.core.Cluster}.
|
||||
* The lifecycle of {@link CassandraClusterFactoryBean} executes {@link #getStartupScripts() startup} and
|
||||
* {@link #getShutdownScripts() shutdown} scripts.
|
||||
*
|
||||
* @return the {@link CassandraClusterFactoryBean}.
|
||||
* @see #cluster()
|
||||
* @see #getStartupScripts()
|
||||
* @see #getShutdownScripts()
|
||||
*/
|
||||
@Bean
|
||||
public CassandraClusterFactoryBean cluster() {
|
||||
|
||||
CassandraClusterFactoryBean bean = new CassandraClusterFactoryBean();
|
||||
|
||||
bean.setAddressTranslator(getAddressTranslator());
|
||||
bean.setAuthProvider(getAuthProvider());
|
||||
bean.setClusterBuilderConfigurer(getClusterBuilderConfigurer());
|
||||
bean.setClusterName(getClusterName());
|
||||
bean.setCompressionType(getCompressionType());
|
||||
bean.setContactPoints(getContactPoints());
|
||||
bean.setLoadBalancingPolicy(getLoadBalancingPolicy());
|
||||
bean.setMaxSchemaAgreementWaitSeconds(getMaxSchemaAgreementWaitSeconds());
|
||||
bean.setMetricsEnabled(getMetricsEnabled());
|
||||
bean.setNettyOptions(getNettyOptions());
|
||||
bean.setPoolingOptions(getPoolingOptions());
|
||||
bean.setPort(getPort());
|
||||
bean.setProtocolVersion(getProtocolVersion());
|
||||
bean.setQueryOptions(getQueryOptions());
|
||||
bean.setReconnectionPolicy(getReconnectionPolicy());
|
||||
bean.setRetryPolicy(getRetryPolicy());
|
||||
bean.setSpeculativeExecutionPolicy(getSpeculativeExecutionPolicy());
|
||||
bean.setSocketOptions(getSocketOptions());
|
||||
bean.setTimestampGenerator(getTimestampGenerator());
|
||||
|
||||
bean.setKeyspaceCreations(getKeyspaceCreations());
|
||||
bean.setKeyspaceDrops(getKeyspaceDrops());
|
||||
bean.setStartupScripts(getStartupScripts());
|
||||
bean.setShutdownScripts(getShutdownScripts());
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AddressTranslator}.
|
||||
*
|
||||
* @return the {@link AddressTranslator}; may be {@literal null}.
|
||||
* @since 1.5
|
||||
*/
|
||||
@Nullable
|
||||
protected AddressTranslator getAddressTranslator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AuthProvider}.
|
||||
*
|
||||
* @return the {@link AuthProvider}, may be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
protected AuthProvider getAuthProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ClusterBuilderConfigurer}.
|
||||
*
|
||||
* @return the {@link ClusterBuilderConfigurer}; may be {@literal null}.
|
||||
* @since 1.5
|
||||
*/
|
||||
@Nullable
|
||||
protected ClusterBuilderConfigurer getClusterBuilderConfigurer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cluster name.
|
||||
*
|
||||
* @return the cluster name; may be {@literal null}.
|
||||
* @since 1.5
|
||||
*/
|
||||
@Nullable
|
||||
protected String getClusterName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link CompressionType}.
|
||||
*
|
||||
* @return the {@link CompressionType}, may be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
protected CompressionType getCompressionType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Cassandra contact points. Defaults to {@code localhost}
|
||||
*
|
||||
* @return the Cassandra contact points
|
||||
* @see CassandraClusterFactoryBean#DEFAULT_CONTACT_POINTS
|
||||
*/
|
||||
protected String getContactPoints() {
|
||||
return CassandraClusterFactoryBean.DEFAULT_CONTACT_POINTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link LoadBalancingPolicy}.
|
||||
*
|
||||
* @return the {@link LoadBalancingPolicy}, may be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
protected LoadBalancingPolicy getLoadBalancingPolicy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum schema agreement wait in seconds.
|
||||
*
|
||||
* @return the maximum schema agreement wait in seconds; default to {@literal 10} seconds.
|
||||
*/
|
||||
protected int getMaxSchemaAgreementWaitSeconds() {
|
||||
return CassandraClusterFactoryBean.DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the whether to enable metrics. Defaults to {@literal true}
|
||||
*
|
||||
* @return {@literal true} to enable metrics.
|
||||
* @see CassandraClusterFactoryBean#DEFAULT_METRICS_ENABLED
|
||||
*/
|
||||
protected boolean getMetricsEnabled() {
|
||||
return CassandraClusterFactoryBean.DEFAULT_METRICS_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link NettyOptions}. Defaults to {@link NettyOptions#DEFAULT_INSTANCE}.
|
||||
*
|
||||
* @return the {@link NettyOptions} to customize netty behavior.
|
||||
* @since 1.5
|
||||
*/
|
||||
protected NettyOptions getNettyOptions() {
|
||||
return NettyOptions.DEFAULT_INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PoolingOptions}.
|
||||
*
|
||||
* @return the {@link PoolingOptions}, may be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
protected PoolingOptions getPoolingOptions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Cassandra port. Defaults to {@code 9042}.
|
||||
*
|
||||
* @return the Cassandra port
|
||||
* @see CassandraClusterFactoryBean#DEFAULT_PORT
|
||||
*/
|
||||
protected int getPort() {
|
||||
return CassandraClusterFactoryBean.DEFAULT_PORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ProtocolVersion}. Defaults to {@link ProtocolVersion#NEWEST_SUPPORTED}.
|
||||
*
|
||||
* @return the {@link ProtocolVersion}.
|
||||
* @see ProtocolVersion#NEWEST_SUPPORTED.
|
||||
*/
|
||||
protected ProtocolVersion getProtocolVersion() {
|
||||
return ProtocolVersion.NEWEST_SUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link QueryOptions}.
|
||||
*
|
||||
* @return the {@link QueryOptions}, may be {@literal null}.
|
||||
* @since 1.5
|
||||
*/
|
||||
@Nullable
|
||||
protected QueryOptions getQueryOptions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ReconnectionPolicy}.
|
||||
*
|
||||
* @return the {@link ReconnectionPolicy}, may be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
protected ReconnectionPolicy getReconnectionPolicy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link RetryPolicy}.
|
||||
*
|
||||
* @return the {@link RetryPolicy}, may be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
protected RetryPolicy getRetryPolicy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SpeculativeExecutionPolicy}.
|
||||
*
|
||||
* @return the {@link SpeculativeExecutionPolicy}; may be {@literal null}.
|
||||
* @since 1.5
|
||||
*/
|
||||
@Nullable
|
||||
protected SpeculativeExecutionPolicy getSpeculativeExecutionPolicy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SocketOptions}.
|
||||
*
|
||||
* @return the {@link SocketOptions}, may be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
protected SocketOptions getSocketOptions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TimestampGenerator}.
|
||||
*
|
||||
* @return the {@link TimestampGenerator}; may be {@literal null}.
|
||||
* @since 1.5
|
||||
*/
|
||||
@Nullable
|
||||
protected TimestampGenerator getTimestampGenerator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of keyspace creations to be run right after {@link com.datastax.driver.core.Cluster}
|
||||
* initialization.
|
||||
*
|
||||
* @return the list of keyspace creations, may be empty but never {@link null}
|
||||
*/
|
||||
protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of keyspace drops to be run before {@link com.datastax.driver.core.Cluster} shutdown.
|
||||
*
|
||||
* @return the list of keyspace drops, may be empty but never {@link null}
|
||||
*/
|
||||
protected List<DropKeyspaceSpecification> getKeyspaceDrops() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of startup scripts to be run after {@link #getKeyspaceCreations() keyspace creations} and after
|
||||
* {@link com.datastax.driver.core.Cluster} initialization.
|
||||
*
|
||||
* @return the list of startup scripts, may be empty but never {@link null}
|
||||
* @deprecated Use {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer}.
|
||||
*/
|
||||
@Deprecated
|
||||
protected List<String> getStartupScripts() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of shutdown scripts to be run after {@link #getKeyspaceDrops() keyspace drops} and right before
|
||||
* {@link com.datastax.driver.core.Cluster} shutdown.
|
||||
*
|
||||
* @return the list of shutdown scripts, may be empty but never {@link null}
|
||||
* @deprecated Use {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer}.
|
||||
*/
|
||||
@Deprecated
|
||||
protected List<String> getShutdownScripts() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -15,28 +15,20 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.cassandra.core.cql.CqlTemplate;
|
||||
|
||||
/**
|
||||
* Abstract configuration class to create a {@link CqlTemplate} and inheriting {@link com.datastax.driver.core.Session}
|
||||
* and {@link com.datastax.driver.core.Cluster} creation. This class is usually extended by user configuration classes.
|
||||
* Abstract configuration class to create a {@link CqlTemplate} and inheriting
|
||||
* {@link com.datastax.oss.driver.api.core.CqlSession} creation. This class is usually extended by user configuration
|
||||
* classes.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
* @see AbstractSessionConfiguration
|
||||
* @see CqlTemplate
|
||||
* @deprecated since 3.0, use {@link AbstractSessionConfiguration}.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractCqlTemplateConfiguration extends AbstractSessionConfiguration {
|
||||
|
||||
/**
|
||||
* Creates a {@link CqlTemplate} configured with {@link #sessionFactory()}.
|
||||
*
|
||||
* @return the {@link CqlTemplate}.
|
||||
* @see #sessionFactory()
|
||||
*/
|
||||
@Bean
|
||||
public CqlTemplate cqlTemplate() {
|
||||
return new CqlTemplate(sessionFactory());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +15,19 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.cassandra.ReactiveSession;
|
||||
import org.springframework.data.cassandra.ReactiveSessionFactory;
|
||||
import org.springframework.data.cassandra.core.CassandraAdminTemplate;
|
||||
import org.springframework.data.cassandra.core.ReactiveCassandraTemplate;
|
||||
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.core.cql.ReactiveCqlOperations;
|
||||
import org.springframework.data.cassandra.core.cql.ReactiveCqlTemplate;
|
||||
import org.springframework.data.cassandra.core.cql.session.DefaultBridgedReactiveSession;
|
||||
import org.springframework.data.cassandra.core.cql.session.DefaultReactiveSessionFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Extension to {@link AbstractCassandraConfiguration} providing Spring Data Cassandra configuration for Spring Data's
|
||||
@@ -34,6 +38,8 @@ import org.springframework.data.cassandra.core.cql.session.DefaultReactiveSessio
|
||||
*/
|
||||
public abstract class AbstractReactiveCassandraConfiguration extends AbstractCassandraConfiguration {
|
||||
|
||||
private @Nullable BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Creates a {@link ReactiveSession} object. This wraps a {@link com.datastax.driver.core.Session} to expose Cassandra
|
||||
* access in a reactive style.
|
||||
@@ -57,7 +63,7 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas
|
||||
*/
|
||||
@Bean
|
||||
public ReactiveSessionFactory reactiveSessionFactory() {
|
||||
return new DefaultReactiveSessionFactory(reactiveSession());
|
||||
return new DefaultReactiveSessionFactory(beanFactory.getBean(ReactiveSession.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,7 +75,8 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas
|
||||
*/
|
||||
@Bean
|
||||
public ReactiveCassandraTemplate reactiveCassandraTemplate() {
|
||||
return new ReactiveCassandraTemplate(reactiveSessionFactory(), cassandraConverter());
|
||||
return new ReactiveCassandraTemplate(beanFactory.getBean(ReactiveSessionFactory.class),
|
||||
beanFactory.getBean(CassandraConverter.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +87,11 @@ public abstract class AbstractReactiveCassandraConfiguration extends AbstractCas
|
||||
*/
|
||||
@Bean
|
||||
public ReactiveCqlTemplate reactiveCqlTemplate() {
|
||||
return new ReactiveCqlTemplate(reactiveSessionFactory());
|
||||
return new ReactiveCqlTemplate(beanFactory.getBean(ReactiveSessionFactory.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,73 +15,39 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.cassandra.SessionFactory;
|
||||
import org.springframework.data.cassandra.core.cql.CqlTemplate;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.DropKeyspaceSpecification;
|
||||
import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
|
||||
/**
|
||||
* Spring {@link @Configuration} class used to configure a Cassandra client application
|
||||
* {@link com.datastax.driver.core.Session} connected to a Cassandra {@link com.datastax.driver.core.Cluster}. Enables a
|
||||
* Cassandra Keyspace to be specified along with the ability to execute arbitrary CQL on startup as well as shutdown.
|
||||
* Spring {@link @Configuration} class used to configure a Cassandra client application {@link CqlSession} connected to
|
||||
* a Cassandra cluster. Enables a Cassandra Keyspace to be specified along with the ability to execute arbitrary CQL on
|
||||
* startup as well as shutdown.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author John Blum
|
||||
* @author Mark Paluch
|
||||
* @see AbstractClusterConfiguration
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
*/
|
||||
@Configuration
|
||||
public abstract class AbstractSessionConfiguration extends AbstractClusterConfiguration {
|
||||
public abstract class AbstractSessionConfiguration implements BeanFactoryAware {
|
||||
|
||||
/**
|
||||
* Returns the initialized {@link Session} instance.
|
||||
*
|
||||
* @return the {@link Session}.
|
||||
* @throws IllegalStateException if the session factory is not initialized.
|
||||
*/
|
||||
protected Session getRequiredSession() {
|
||||
|
||||
CassandraCqlSessionFactoryBean factoryBean = session();
|
||||
Assert.state(factoryBean.getObject() != null, "Session factory not initialized");
|
||||
|
||||
return factoryBean.getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link CassandraCqlSessionFactoryBean} that provides a Cassandra
|
||||
* {@link com.datastax.driver.core.Session}.
|
||||
*
|
||||
* @return the {@link CassandraCqlSessionFactoryBean}.
|
||||
* @see #cluster()
|
||||
* @see #getKeyspaceName()
|
||||
*/
|
||||
@Bean
|
||||
public CassandraCqlSessionFactoryBean session() {
|
||||
|
||||
CassandraCqlSessionFactoryBean bean = new CassandraCqlSessionFactoryBean();
|
||||
|
||||
bean.setCluster(getRequiredCluster());
|
||||
bean.setKeyspaceName(getKeyspaceName());
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link DefaultSessionFactory} using the configured {@link #session()} to be used with
|
||||
* {@link CqlTemplate}.
|
||||
*
|
||||
* @return {@link SessionFactory} used to initialize the Template API.
|
||||
* @since 2.0
|
||||
*/
|
||||
@Bean
|
||||
public SessionFactory sessionFactory() {
|
||||
return new DefaultSessionFactory(getRequiredSession());
|
||||
}
|
||||
private @Nullable BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Return the name of the keyspace to connect to.
|
||||
@@ -89,4 +55,169 @@ public abstract class AbstractSessionConfiguration extends AbstractClusterConfig
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
protected abstract String getKeyspaceName();
|
||||
|
||||
/**
|
||||
* Returns the initialized {@link CqlSession} instance.
|
||||
*
|
||||
* @return the {@link CqlSession}.
|
||||
* @throws IllegalStateException if the session factory is not initialized.
|
||||
*/
|
||||
protected SessionFactory getRequiredSessionFactory() {
|
||||
|
||||
ObjectProvider<SessionFactory> beanProvider = beanFactory.getBeanProvider(SessionFactory.class);
|
||||
|
||||
return beanProvider.getIfAvailable(() -> new DefaultSessionFactory(beanFactory.getBean(CqlSession.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link SessionBuilderConfigurer}.
|
||||
*
|
||||
* @return the {@link SessionBuilderConfigurer}; may be {@literal null}.
|
||||
* @since 1.5
|
||||
*/
|
||||
@Nullable
|
||||
protected SessionBuilderConfigurer getClusterBuilderConfigurer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cluster name.
|
||||
*
|
||||
* @return the cluster name; may be {@literal null}.
|
||||
* @since 1.5
|
||||
*/
|
||||
@Nullable
|
||||
protected String getClusterName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link CompressionType}.
|
||||
*
|
||||
* @return the {@link CompressionType}, may be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
protected CompressionType getCompressionType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Cassandra contact points. Defaults to {@code localhost}
|
||||
*
|
||||
* @return the Cassandra contact points
|
||||
* @see CqlSessionFactoryBean#DEFAULT_CONTACT_POINTS
|
||||
*/
|
||||
protected String getContactPoints() {
|
||||
return CqlSessionFactoryBean.DEFAULT_CONTACT_POINTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Cassandra port. Defaults to {@code 9042}.
|
||||
*
|
||||
* @return the Cassandra port
|
||||
* @see CqlSessionFactoryBean#DEFAULT_PORT
|
||||
*/
|
||||
protected int getPort() {
|
||||
return CqlSessionFactoryBean.DEFAULT_PORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of keyspace creations to be run right after initialization.
|
||||
*
|
||||
* @return the list of keyspace creations, may be empty but never {@link null}
|
||||
*/
|
||||
protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of keyspace drops to be run before shutdown.
|
||||
*
|
||||
* @return the list of keyspace drops, may be empty but never {@link null}
|
||||
*/
|
||||
protected List<DropKeyspaceSpecification> getKeyspaceDrops() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of startup scripts to be run after {@link #getKeyspaceCreations() keyspace creations} and after
|
||||
* initialization.
|
||||
*
|
||||
* @return the list of startup scripts, may be empty but never {@link null}
|
||||
* @deprecated since 3.0, declare a
|
||||
* {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer} bean.
|
||||
*/
|
||||
@Deprecated
|
||||
protected List<String> getStartupScripts() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of shutdown scripts to be run after {@link #getKeyspaceDrops() keyspace drops} and right before
|
||||
* shutdown.
|
||||
*
|
||||
* @return the list of shutdown scripts, may be empty but never {@link null}
|
||||
* @deprecated since 3.0, declare a
|
||||
* {@link org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer} bean.
|
||||
*/
|
||||
@Deprecated
|
||||
protected List<String> getShutdownScripts() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initialized {@link CqlSession} instance.
|
||||
*
|
||||
* @return the {@link CqlSession}.
|
||||
* @throws IllegalStateException if the session factory is not initialized.
|
||||
*/
|
||||
protected CqlSession getRequiredSession() {
|
||||
|
||||
Assert.state(beanFactory != null, "BeanFactory not initialized");
|
||||
|
||||
return beanFactory.getBean(CqlSession.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link CqlSessionFactoryBean} that provides a Cassandra {@link CqlSession}.
|
||||
*
|
||||
* @return the {@link CqlSessionFactoryBean}.
|
||||
* @see #getKeyspaceName()
|
||||
* @see #getStartupScripts()
|
||||
* @see #getShutdownScripts()
|
||||
*/
|
||||
@Bean
|
||||
public CqlSessionFactoryBean session() {
|
||||
|
||||
CqlSessionFactoryBean bean = new CqlSessionFactoryBean();
|
||||
|
||||
bean.setContactPoints(getContactPoints());
|
||||
bean.setPort(getPort());
|
||||
|
||||
bean.setKeyspaceCreations(getKeyspaceCreations());
|
||||
bean.setKeyspaceDrops(getKeyspaceDrops());
|
||||
|
||||
bean.setKeyspaceName(getKeyspaceName());
|
||||
bean.setKeyspaceStartupScripts(getStartupScripts());
|
||||
bean.setKeyspaceShutdownScripts(getShutdownScripts());
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link CqlTemplate} configured with {@link #getRequiredSessionFactory()}.
|
||||
*
|
||||
* @return the {@link CqlTemplate}.
|
||||
* @see #getRequiredSession()
|
||||
*/
|
||||
@Bean
|
||||
public CqlTemplate cqlTemplate() {
|
||||
return new CqlTemplate(getRequiredSessionFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,749 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.cassandra.core.cql.CassandraExceptionTranslator;
|
||||
import org.springframework.data.cassandra.core.cql.CqlTemplate;
|
||||
import org.springframework.data.cassandra.core.cql.generator.AlterKeyspaceCqlGenerator;
|
||||
import org.springframework.data.cassandra.core.cql.generator.CreateKeyspaceCqlGenerator;
|
||||
import org.springframework.data.cassandra.core.cql.generator.DropKeyspaceCqlGenerator;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.AlterKeyspaceSpecification;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.DropKeyspaceSpecification;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceActionSpecification;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.datastax.driver.core.*;
|
||||
import com.datastax.driver.core.Cluster.Builder;
|
||||
import com.datastax.driver.core.ProtocolOptions.Compression;
|
||||
import com.datastax.driver.core.policies.AddressTranslator;
|
||||
import com.datastax.driver.core.policies.LoadBalancingPolicy;
|
||||
import com.datastax.driver.core.policies.ReconnectionPolicy;
|
||||
import com.datastax.driver.core.policies.RetryPolicy;
|
||||
import com.datastax.driver.core.policies.SpeculativeExecutionPolicy;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.FactoryBean} for configuring a Cassandra {@link Cluster}.
|
||||
* <p>
|
||||
* This factory bean allows configuration and creation of {@link Cluster} bean. Most options default to {@literal null}.
|
||||
* Unsupported options are configured via {@link ClusterBuilderConfigurer}.
|
||||
* <p/>
|
||||
* The factory bean initializes keyspaces, if configured, accoording to its lifecycle. Keyspaces can be created after
|
||||
* {@link #afterPropertiesSet() initialization} and dropped when this factory is {@link #destroy() destroyed}. Keyspace
|
||||
* actions can be configured via {@link #setKeyspaceActions(List) XML} and {@link #setKeyspaceCreations(List)
|
||||
* programatically}. Additional {@link #getStartupScripts()} and {@link #getShutdownScripts()} are executed after
|
||||
* running keyspace actions.
|
||||
* <p/>
|
||||
* <strong>XML configuration</strong>
|
||||
*
|
||||
* <pre class="code">
|
||||
<cql:cluster contact-points="…"
|
||||
port="${build.cassandra.native_transport_port}" compression="SNAPPY" netty-options-ref="nettyOptions">
|
||||
<cql:local-pooling-options
|
||||
min-simultaneous-requests="26" max-simultaneous-requests="101"
|
||||
core-connections="3" max-connections="9"/>
|
||||
<cql:remote-pooling-options
|
||||
min-simultaneous-requests="25" max-simultaneous-requests="100"
|
||||
core-connections="1" max-connections="2"/>
|
||||
<cql:socket-options connect-timeout-millis="5000"
|
||||
keep-alive="true" reuse-address="true" so-linger="60" tcp-no-delay="true"
|
||||
receive-buffer-size="65536" send-buffer-size="65536"/>
|
||||
<cql:keyspace name="${cassandra.keyspace}" action="CREATE_DROP"
|
||||
durable-writes="true"/>
|
||||
</cass:cluster>
|
||||
* </pre>
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
* @author David Webb
|
||||
* @author Kirk Clemens
|
||||
* @author Jorge Davison
|
||||
* @author John Blum
|
||||
* @author Mark Paluch
|
||||
* @author Stefan Birkner
|
||||
* @see org.springframework.beans.factory.InitializingBean
|
||||
* @see org.springframework.beans.factory.DisposableBean
|
||||
* @see org.springframework.beans.factory.FactoryBean
|
||||
* @see com.datastax.driver.core.Cluster
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class CassandraClusterFactoryBean
|
||||
implements FactoryBean<Cluster>, InitializingBean, DisposableBean, BeanNameAware, PersistenceExceptionTranslator {
|
||||
|
||||
public static final boolean DEFAULT_JMX_REPORTING_ENABLED = true;
|
||||
public static final boolean DEFAULT_METRICS_ENABLED = true;
|
||||
public static final boolean DEFAULT_SSL_ENABLED = false;
|
||||
|
||||
public static final int DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS = 10;
|
||||
public static final int DEFAULT_PORT = 9042;
|
||||
|
||||
public static final String DEFAULT_CONTACT_POINTS = "localhost";
|
||||
|
||||
protected static final Logger log = LoggerFactory.getLogger(CassandraCqlClusterFactoryBean.class);
|
||||
|
||||
private boolean jmxReportingEnabled = DEFAULT_JMX_REPORTING_ENABLED;
|
||||
private boolean metricsEnabled = DEFAULT_METRICS_ENABLED;
|
||||
private boolean sslEnabled = DEFAULT_SSL_ENABLED;
|
||||
|
||||
private int maxSchemaAgreementWaitSeconds = DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS;
|
||||
private int port = DEFAULT_PORT;
|
||||
|
||||
private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
|
||||
|
||||
private @Nullable Cluster cluster;
|
||||
private @Nullable ClusterBuilderConfigurer clusterBuilderConfigurer;
|
||||
|
||||
private @Nullable AddressTranslator addressTranslator;
|
||||
private @Nullable AuthProvider authProvider;
|
||||
private @Nullable CompressionType compressionType;
|
||||
private @Nullable CodecRegistry codecRegistry;
|
||||
private @Nullable Host.StateListener hostStateListener;
|
||||
private @Nullable LatencyTracker latencyTracker;
|
||||
private @Nullable LoadBalancingPolicy loadBalancingPolicy;
|
||||
private NettyOptions nettyOptions = NettyOptions.DEFAULT_INSTANCE;
|
||||
private @Nullable PoolingOptions poolingOptions;
|
||||
private @Nullable ProtocolVersion protocolVersion;
|
||||
private @Nullable QueryOptions queryOptions;
|
||||
private @Nullable ReconnectionPolicy reconnectionPolicy;
|
||||
private @Nullable RetryPolicy retryPolicy;
|
||||
private @Nullable SpeculativeExecutionPolicy speculativeExecutionPolicy;
|
||||
private @Nullable SocketOptions socketOptions;
|
||||
private @Nullable SSLOptions sslOptions;
|
||||
private @Nullable TimestampGenerator timestampGenerator;
|
||||
|
||||
private List<AlterKeyspaceSpecification> keyspaceAlterations = new ArrayList<>();
|
||||
private List<CreateKeyspaceSpecification> keyspaceCreations = new ArrayList<>();
|
||||
private List<DropKeyspaceSpecification> keyspaceDrops = new ArrayList<>();
|
||||
private List<KeyspaceActions> keyspaceActions = new ArrayList<>();
|
||||
private List<String> startupScripts = new ArrayList<>();
|
||||
private List<String> shutdownScripts = new ArrayList<>();
|
||||
|
||||
private Set<KeyspaceActionSpecification> keyspaceSpecifications = new HashSet<>();
|
||||
|
||||
private @Nullable String beanName;
|
||||
private @Nullable String clusterName;
|
||||
private String contactPoints = DEFAULT_CONTACT_POINTS;
|
||||
private @Nullable String password;
|
||||
private @Nullable String username;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.cluster = initializeCluster(withRegistrations(buildCluster()));
|
||||
}
|
||||
|
||||
private @NonNull Cluster buildCluster() {
|
||||
|
||||
Assert.hasText(this.contactPoints, "At least one server is required");
|
||||
|
||||
Builder clusterBuilder = newClusterBuilder()
|
||||
.addContactPoints(StringUtils.commaDelimitedListToStringArray(this.contactPoints))
|
||||
.withMaxSchemaAgreementWaitSeconds(this.maxSchemaAgreementWaitSeconds).withPort(this.port);
|
||||
|
||||
Optional.ofNullable(this.addressTranslator).ifPresent(clusterBuilder::withAddressTranslator);
|
||||
Optional.ofNullable(this.codecRegistry).ifPresent(clusterBuilder::withCodecRegistry);
|
||||
Optional.ofNullable(this.loadBalancingPolicy).ifPresent(clusterBuilder::withLoadBalancingPolicy);
|
||||
Optional.ofNullable(this.nettyOptions).ifPresent(clusterBuilder::withNettyOptions);
|
||||
Optional.ofNullable(this.poolingOptions).ifPresent(clusterBuilder::withPoolingOptions);
|
||||
Optional.ofNullable(this.protocolVersion).ifPresent(clusterBuilder::withProtocolVersion);
|
||||
Optional.ofNullable(this.queryOptions).ifPresent(clusterBuilder::withQueryOptions);
|
||||
Optional.ofNullable(this.reconnectionPolicy).ifPresent(clusterBuilder::withReconnectionPolicy);
|
||||
Optional.ofNullable(this.retryPolicy).ifPresent(clusterBuilder::withRetryPolicy);
|
||||
Optional.ofNullable(this.socketOptions).ifPresent(clusterBuilder::withSocketOptions);
|
||||
Optional.ofNullable(this.speculativeExecutionPolicy).ifPresent(clusterBuilder::withSpeculativeExecutionPolicy);
|
||||
Optional.ofNullable(this.timestampGenerator).ifPresent(clusterBuilder::withTimestampGenerator);
|
||||
|
||||
Optional.ofNullable(this.authProvider).map(clusterBuilder::withAuthProvider).orElseGet(
|
||||
() -> StringUtils.hasText(this.username) ? clusterBuilder.withCredentials(this.username, this.password)
|
||||
: clusterBuilder);
|
||||
|
||||
Optional.ofNullable(this.compressionType).map(CassandraClusterFactoryBean::convertCompressionType)
|
||||
.ifPresent(clusterBuilder::withCompression);
|
||||
|
||||
if (!this.jmxReportingEnabled) {
|
||||
clusterBuilder.withoutJMXReporting();
|
||||
}
|
||||
|
||||
if (!this.metricsEnabled) {
|
||||
clusterBuilder.withoutMetrics();
|
||||
}
|
||||
|
||||
if (this.sslEnabled) {
|
||||
Optional.ofNullable(this.sslOptions).map(clusterBuilder::withSSL).orElseGet(clusterBuilder::withSSL);
|
||||
}
|
||||
|
||||
Optional.ofNullable(resolveClusterName()).filter(StringUtils::hasText).ifPresent(clusterBuilder::withClusterName);
|
||||
|
||||
if (this.clusterBuilderConfigurer != null) {
|
||||
this.clusterBuilderConfigurer.configure(clusterBuilder);
|
||||
}
|
||||
|
||||
return clusterBuilder.build();
|
||||
}
|
||||
|
||||
private static Compression convertCompressionType(CompressionType type) {
|
||||
|
||||
switch (type) {
|
||||
case NONE:
|
||||
return Compression.NONE;
|
||||
case SNAPPY:
|
||||
return Compression.SNAPPY;
|
||||
case LZ4:
|
||||
return Compression.LZ4;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Unknown compression type [%s]", type));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.datastax.driver.core.Cluster#builder()
|
||||
*/
|
||||
@NonNull
|
||||
Cluster.Builder newClusterBuilder() {
|
||||
return Cluster.builder();
|
||||
}
|
||||
|
||||
private @Nullable String resolveClusterName() {
|
||||
return StringUtils.hasText(this.clusterName) ? this.clusterName : this.beanName;
|
||||
}
|
||||
|
||||
private @NonNull Cluster withRegistrations(@NonNull Cluster cluster) {
|
||||
|
||||
Optional.ofNullable(this.hostStateListener).ifPresent(cluster::register);
|
||||
Optional.ofNullable(this.latencyTracker).ifPresent(cluster::register);
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
private @NonNull Cluster initializeCluster(@NonNull Cluster cluster) {
|
||||
|
||||
generateSpecificationsFromFactoryBeans();
|
||||
|
||||
List<KeyspaceActionSpecification> startupSpecifications = new ArrayList<>(
|
||||
this.keyspaceCreations.size() + this.keyspaceAlterations.size());
|
||||
|
||||
startupSpecifications.addAll(this.keyspaceCreations);
|
||||
startupSpecifications.addAll(this.keyspaceAlterations);
|
||||
|
||||
executeSpecsAndScripts(startupSpecifications, this.startupScripts, cluster);
|
||||
|
||||
return cluster;
|
||||
}
|
||||
|
||||
private void executeSpecsAndScripts(List<? extends KeyspaceActionSpecification> keyspaceActionSpecifications,
|
||||
List<String> scripts, Cluster cluster) {
|
||||
|
||||
if (!CollectionUtils.isEmpty(keyspaceActionSpecifications) || !CollectionUtils.isEmpty(scripts)) {
|
||||
|
||||
try (Session session = cluster.connect()) {
|
||||
|
||||
CqlTemplate template = new CqlTemplate(session);
|
||||
|
||||
keyspaceActionSpecifications
|
||||
.forEach(keyspaceActionSpecification -> template.execute(toCql(keyspaceActionSpecification)));
|
||||
|
||||
scripts.forEach(template::execute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the contents of all the KeyspaceSpecificationFactoryBeans and generates the proper KeyspaceSpecification
|
||||
* from them.
|
||||
*/
|
||||
private void generateSpecificationsFromFactoryBeans() {
|
||||
|
||||
generateSpecifications(this.keyspaceSpecifications);
|
||||
this.keyspaceActions.forEach(actions -> generateSpecifications(actions.getActions()));
|
||||
}
|
||||
|
||||
private void generateSpecifications(Collection<KeyspaceActionSpecification> specifications) {
|
||||
|
||||
specifications.forEach(keyspaceActionSpecification -> {
|
||||
|
||||
if (keyspaceActionSpecification instanceof AlterKeyspaceSpecification) {
|
||||
this.keyspaceAlterations.add((AlterKeyspaceSpecification) keyspaceActionSpecification);
|
||||
} else if (keyspaceActionSpecification instanceof CreateKeyspaceSpecification) {
|
||||
this.keyspaceCreations.add((CreateKeyspaceSpecification) keyspaceActionSpecification);
|
||||
} else if (keyspaceActionSpecification instanceof DropKeyspaceSpecification) {
|
||||
this.keyspaceDrops.add((DropKeyspaceSpecification) keyspaceActionSpecification);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String toCql(KeyspaceActionSpecification specification) {
|
||||
|
||||
if (specification instanceof AlterKeyspaceSpecification) {
|
||||
return new AlterKeyspaceCqlGenerator((AlterKeyspaceSpecification) specification).toCql();
|
||||
} else if (specification instanceof CreateKeyspaceSpecification) {
|
||||
return new CreateKeyspaceCqlGenerator((CreateKeyspaceSpecification) specification).toCql();
|
||||
} else if (specification instanceof DropKeyspaceSpecification) {
|
||||
return new DropKeyspaceCqlGenerator((DropKeyspaceSpecification) specification).toCql();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported specification type: " + ClassUtils.getQualifiedName(specification.getClass()));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||
*/
|
||||
@Override
|
||||
public Cluster getObject() {
|
||||
return this.cluster;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
@Override
|
||||
public Class<? extends Cluster> getObjectType() {
|
||||
return this.cluster != null ? this.cluster.getClass() : Cluster.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
||||
*/
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
if (this.cluster != null) {
|
||||
executeSpecsAndScripts(this.keyspaceDrops, this.shutdownScripts, this.cluster);
|
||||
this.cluster.close();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
*/
|
||||
@Override
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException cause) {
|
||||
return exceptionTranslator.translateExceptionIfPossible(cause);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(String)
|
||||
* @since 1.5
|
||||
*/
|
||||
@Override
|
||||
public void setBeanName(@Nullable String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a comma-delimited string of the contact points (hosts) to connect to. Default is {@code localhost}; see
|
||||
* {@link #DEFAULT_CONTACT_POINTS}.
|
||||
*
|
||||
* @param contactPoints the contact points used by the new cluster.
|
||||
*/
|
||||
public void setContactPoints(String contactPoints) {
|
||||
this.contactPoints = contactPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the port for the contact points. Default is {@code 9042}, see {@link #DEFAULT_PORT}.
|
||||
*
|
||||
* @param port the port used by the new cluster.
|
||||
*/
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link CompressionType}. Default is uncompressed.
|
||||
*
|
||||
* @param compressionType the {@link CompressionType} used by the new cluster.
|
||||
*/
|
||||
public void setCompressionType(@Nullable CompressionType compressionType) {
|
||||
this.compressionType = compressionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link CodecRegistry}. Default uses {@link CodecRegistry#DEFAULT_INSTANCE}.
|
||||
*
|
||||
* @param codecRegistry the {@link CodecRegistry} used by the new cluster.
|
||||
* @since 2.2
|
||||
*/
|
||||
public void setCodecRegistry(@Nullable CodecRegistry codecRegistry) {
|
||||
this.codecRegistry = codecRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link PoolingOptions} to configure the connection pooling behavior.
|
||||
*
|
||||
* @param poolingOptions the {@link PoolingOptions} used by the new cluster.
|
||||
*/
|
||||
public void setPoolingOptions(@Nullable PoolingOptions poolingOptions) {
|
||||
this.poolingOptions = poolingOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ProtocolVersion}.
|
||||
*
|
||||
* @param protocolVersion the {@link ProtocolVersion} used by the new cluster.
|
||||
* @since 1.4
|
||||
*/
|
||||
public void setProtocolVersion(@Nullable ProtocolVersion protocolVersion) {
|
||||
this.protocolVersion = protocolVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SocketOptions} containing low-level socket options.
|
||||
*
|
||||
* @param socketOptions the {@link SocketOptions} used by the new cluster.
|
||||
*/
|
||||
public void setSocketOptions(@Nullable SocketOptions socketOptions) {
|
||||
this.socketOptions = socketOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link QueryOptions} to tune to defaults for individual queries.
|
||||
*
|
||||
* @param queryOptions the {@link QueryOptions} used by the new cluster.
|
||||
*/
|
||||
public void setQueryOptions(@Nullable QueryOptions queryOptions) {
|
||||
this.queryOptions = queryOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link AuthProvider}. Default is unauthenticated.
|
||||
*
|
||||
* @param authProvider the {@link AuthProvider} used by the new cluster.
|
||||
*/
|
||||
public void setAuthProvider(@Nullable AuthProvider authProvider) {
|
||||
this.authProvider = authProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link NettyOptions} used by a client to customize the driver's underlying Netty layer.
|
||||
*
|
||||
* @param nettyOptions the {@link NettyOptions} used by the new cluster.
|
||||
* @since 1.5
|
||||
*/
|
||||
public void setNettyOptions(NettyOptions nettyOptions) {
|
||||
this.nettyOptions = nettyOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link LoadBalancingPolicy} that decides which Cassandra hosts to contact for each new query.
|
||||
*
|
||||
* @param loadBalancingPolicy the {@link LoadBalancingPolicy} used by the new cluster.
|
||||
*/
|
||||
public void setLoadBalancingPolicy(@Nullable LoadBalancingPolicy loadBalancingPolicy) {
|
||||
this.loadBalancingPolicy = loadBalancingPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ReconnectionPolicy} that decides how often the reconnection to a dead node is attempted.
|
||||
*
|
||||
* @param reconnectionPolicy the {@link ReconnectionPolicy} used by the new cluster.
|
||||
*/
|
||||
public void setReconnectionPolicy(@Nullable ReconnectionPolicy reconnectionPolicy) {
|
||||
this.reconnectionPolicy = reconnectionPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link RetryPolicy} that defines a default behavior to adopt when a request fails.
|
||||
*
|
||||
* @param retryPolicy the {@link RetryPolicy} used by the new cluster.
|
||||
*/
|
||||
public void setRetryPolicy(@Nullable RetryPolicy retryPolicy) {
|
||||
this.retryPolicy = retryPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether metrics are enabled. Default is {@literal true}, see {@link #DEFAULT_METRICS_ENABLED}.
|
||||
*/
|
||||
public void setMetricsEnabled(boolean metricsEnabled) {
|
||||
this.metricsEnabled = metricsEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link List} of {@link KeyspaceActions}.
|
||||
*/
|
||||
public List<KeyspaceActions> getKeyspaceActions() {
|
||||
return Collections.unmodifiableList(this.keyspaceActions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link List} of {@link KeyspaceActions} to be executed on initialization. Keyspace actions may contain create
|
||||
* and drop specifications.
|
||||
*
|
||||
* @param keyspaceActions the {@link List} of {@link KeyspaceActions}.
|
||||
*/
|
||||
public void setKeyspaceActions(List<KeyspaceActions> keyspaceActions) {
|
||||
this.keyspaceActions = new ArrayList<>(keyspaceActions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link List} of {@link CreateKeyspaceSpecification create keyspace specifications} that are executed when
|
||||
* this factory is {@link #afterPropertiesSet() initialized}. {@link CreateKeyspaceSpecification Create keyspace
|
||||
* specifications} are executed on a system session with no keyspace set, before executing
|
||||
* {@link #setStartupScripts(List)}.
|
||||
*
|
||||
* @param specifications the {@link List} of {@link CreateKeyspaceSpecification create keyspace specifications}.
|
||||
*/
|
||||
public void setKeyspaceCreations(List<CreateKeyspaceSpecification> specifications) {
|
||||
this.keyspaceCreations = new ArrayList<>(specifications);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link List} of {@link CreateKeyspaceSpecification create keyspace specifications}.
|
||||
*/
|
||||
public List<CreateKeyspaceSpecification> getKeyspaceCreations() {
|
||||
return Collections.unmodifiableList(keyspaceCreations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link List} of {@link DropKeyspaceSpecification drop keyspace specifications} that are executed when this
|
||||
* factory is {@link #destroy() destroyed}. {@link DropKeyspaceSpecification Drop keyspace specifications} are
|
||||
* executed on a system session with no keyspace set, before executing {@link #setShutdownScripts(List)}.
|
||||
*
|
||||
* @param specifications the {@link List} of {@link DropKeyspaceSpecification drop keyspace specifications}.
|
||||
*/
|
||||
public void setKeyspaceDrops(List<DropKeyspaceSpecification> specifications) {
|
||||
this.keyspaceDrops = new ArrayList<>(specifications);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link List} of {@link DropKeyspaceSpecification drop keyspace specifications}.
|
||||
*/
|
||||
public List<DropKeyspaceSpecification> getKeyspaceDrops() {
|
||||
return Collections.unmodifiableList(keyspaceDrops);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link List} of raw {@link String CQL statements} that are executed when this factory is
|
||||
* {@link #afterPropertiesSet() initialized}. Scripts are executed on a system session with no keyspace set, after
|
||||
* executing {@link #setKeyspaceCreations(List)}.
|
||||
*
|
||||
* @param scripts the scripts to execute on startup
|
||||
*/
|
||||
public void setStartupScripts(List<String> scripts) {
|
||||
this.startupScripts = new ArrayList<>(scripts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the startup scripts
|
||||
*/
|
||||
public List<String> getStartupScripts() {
|
||||
return Collections.unmodifiableList(this.startupScripts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link List} of raw {@link String CQL statements} that are executed when this factory is {@link #destroy()
|
||||
* destroyed}. {@link DropKeyspaceSpecification Drop keyspace specifications} are executed on a system session with no
|
||||
* keyspace set, after executing {@link #setKeyspaceDrops(List)}.
|
||||
*
|
||||
* @param scripts the scripts to execute on shutdown
|
||||
*/
|
||||
public void setShutdownScripts(List<String> scripts) {
|
||||
this.shutdownScripts = new ArrayList<>(scripts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the shutdown scripts
|
||||
*/
|
||||
public List<String> getShutdownScripts() {
|
||||
return Collections.unmodifiableList(this.shutdownScripts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param keyspaceSpecifications The {@link KeyspaceActionSpecification} to set.
|
||||
*/
|
||||
public void setKeyspaceSpecifications(Set<KeyspaceActionSpecification> keyspaceSpecifications) {
|
||||
this.keyspaceSpecifications = new LinkedHashSet<>(keyspaceSpecifications);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link KeyspaceActionSpecification} associated with this factory.
|
||||
*/
|
||||
public Set<KeyspaceActionSpecification> getKeyspaceSpecifications() {
|
||||
return Collections.unmodifiableSet(this.keyspaceSpecifications);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username to use with {@link com.datastax.driver.core.PlainTextAuthProvider}.
|
||||
*
|
||||
* @param username The username to set.
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username to use with {@link com.datastax.driver.core.PlainTextAuthProvider}.
|
||||
*
|
||||
* @param password The password to set.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use JMX reporting. Default is {@literal false}, see {@link #DEFAULT_JMX_REPORTING_ENABLED}.
|
||||
*
|
||||
* @param jmxReportingEnabled The jmxReportingEnabled to set.
|
||||
*/
|
||||
public void setJmxReportingEnabled(boolean jmxReportingEnabled) {
|
||||
this.jmxReportingEnabled = jmxReportingEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use SSL. Default is plain, see {@link #DEFAULT_SSL_ENABLED}.
|
||||
*
|
||||
* @param sslEnabled The sslEnabled to set.
|
||||
*/
|
||||
public void setSslEnabled(boolean sslEnabled) {
|
||||
this.sslEnabled = sslEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sslOptions The sslOptions to set.
|
||||
*/
|
||||
public void setSslOptions(SSLOptions sslOptions) {
|
||||
this.sslOptions = sslOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hostStateListener The hostStateListener to set.
|
||||
*/
|
||||
public void setHostStateListener(Host.StateListener hostStateListener) {
|
||||
this.hostStateListener = hostStateListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param latencyTracker {@link LatencyTracker} to set.
|
||||
*/
|
||||
public void setLatencyTracker(LatencyTracker latencyTracker) {
|
||||
this.latencyTracker = latencyTracker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the address translator used by the new cluster to translate IP addresses received from Cassandra nodes
|
||||
* into locally query-able addresses.
|
||||
*
|
||||
* @param addressTranslator {@link AddressTranslator} used by the new cluster.
|
||||
* @see com.datastax.driver.core.Cluster.Builder#withAddressTranslator(AddressTranslator)
|
||||
* @see com.datastax.driver.core.policies.AddressTranslator
|
||||
* @since 1.5
|
||||
*/
|
||||
public void setAddressTranslator(@Nullable AddressTranslator addressTranslator) {
|
||||
this.addressTranslator = addressTranslator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ClusterBuilderConfigurer} used to apply additional configuration logic to the
|
||||
* {@link com.datastax.driver.core.Cluster.Builder} object. {@link ClusterBuilderConfigurer} is invoked after all
|
||||
* provided options are configured. The factory will {@link Builder#build()} the {@link Cluster} after applying
|
||||
* {@link ClusterBuilderConfigurer}.
|
||||
*
|
||||
* @param clusterBuilderConfigurer {@link ClusterBuilderConfigurer} used to configure the
|
||||
* {@link com.datastax.driver.core.Cluster.Builder}.
|
||||
* @see org.springframework.data.cassandra.config.ClusterBuilderConfigurer
|
||||
*/
|
||||
public void setClusterBuilderConfigurer(@Nullable ClusterBuilderConfigurer clusterBuilderConfigurer) {
|
||||
this.clusterBuilderConfigurer = clusterBuilderConfigurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional name for the cluster instance. This name appears in JMX metrics. Defaults to the bean name.
|
||||
*
|
||||
* @param clusterName optional name for the cluster.
|
||||
* @see com.datastax.driver.core.Cluster.Builder#withClusterName(String)
|
||||
* @since 1.5
|
||||
*/
|
||||
public void setClusterName(@Nullable String clusterName) {
|
||||
this.clusterName = clusterName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum time to wait for schema agreement before returning from a DDL query. The timeout is used to wait
|
||||
* for all currently up hosts in the cluster to agree on the schema.
|
||||
*
|
||||
* @param seconds max schema agreement wait in seconds.
|
||||
* @see com.datastax.driver.core.Cluster.Builder#withMaxSchemaAgreementWaitSeconds(int)
|
||||
* @since 1.5
|
||||
*/
|
||||
public void setMaxSchemaAgreementWaitSeconds(int seconds) {
|
||||
this.maxSchemaAgreementWaitSeconds = seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the speculative execution policy to use for the new cluster.
|
||||
*
|
||||
* @param speculativeExecutionPolicy {@link SpeculativeExecutionPolicy} to use with the new cluster.
|
||||
* @see com.datastax.driver.core.Cluster.Builder#withSpeculativeExecutionPolicy(SpeculativeExecutionPolicy)
|
||||
* @see com.datastax.driver.core.policies.SpeculativeExecutionPolicy
|
||||
* @since 1.5
|
||||
*/
|
||||
public void setSpeculativeExecutionPolicy(@Nullable SpeculativeExecutionPolicy speculativeExecutionPolicy) {
|
||||
this.speculativeExecutionPolicy = speculativeExecutionPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the generator that will produce the client-side timestamp sent with each query.
|
||||
*
|
||||
* @param timestampGenerator {@link TimestampGenerator} used to produce a client-side timestamp sent with each query.
|
||||
* @see com.datastax.driver.core.Cluster.Builder#withTimestampGenerator(TimestampGenerator)
|
||||
* @see com.datastax.driver.core.TimestampGenerator
|
||||
* @since 1.5
|
||||
*/
|
||||
public void setTimestampGenerator(@Nullable TimestampGenerator timestampGenerator) {
|
||||
this.timestampGenerator = timestampGenerator;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Spring Data Cassandra XML namespace parser for the {@code cassandra:cluster} element.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class CassandraClusterParser extends CassandraCqlClusterParser {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.cassandra.config.xml.CassandraCqlClusterParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
|
||||
*/
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
|
||||
CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext);
|
||||
|
||||
return super.parseInternal(element, parserContext);
|
||||
}
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import static org.springframework.data.cassandra.config.ParsingUtils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceActionSpecification;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceAttributes;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import com.datastax.driver.core.PoolingOptions;
|
||||
import com.datastax.driver.core.SocketOptions;
|
||||
|
||||
/**
|
||||
* Parses the {@literal <cluster>} element of the XML Configuration.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author David Webb
|
||||
* @author John Blum
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class CassandraCqlClusterParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
|
||||
*/
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
String id = super.resolveId(element, definition, parserContext);
|
||||
|
||||
return StringUtils.hasText(id) ? id : DefaultCqlBeanNames.CLUSTER;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
|
||||
*/
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CassandraClusterFactoryBean.class);
|
||||
|
||||
builder.setLazyInit(parserContext.isDefaultLazyInit());
|
||||
builder.getRawBeanDefinition().setDestroyMethodName("destroy");
|
||||
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
|
||||
|
||||
if (parserContext.isNested()) {
|
||||
// inner bean definitions must have same scope as containing bean
|
||||
builder.setScope(parserContext.getContainingBeanDefinition().getScope());
|
||||
}
|
||||
|
||||
doParse(element, parserContext, builder);
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses cluster meta-data.
|
||||
*
|
||||
* @param element {@link Element} to parse.
|
||||
* @param parserContext XML parser context and state.
|
||||
* @param builder parent {@link BeanDefinitionBuilder}.
|
||||
*/
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
addOptionalPropertyReference(builder, "addressTranslator", element, "address-translator-ref");
|
||||
addOptionalPropertyReference(builder, "authProvider", element, "auth-info-provider-ref");
|
||||
addOptionalPropertyReference(builder, "clusterBuilderConfigurer", element, "cluster-builder-configurer-ref");
|
||||
addOptionalPropertyReference(builder, "hostStateListener", element, "host-state-listener-ref");
|
||||
addOptionalPropertyReference(builder, "latencyTracker", element, "latency-tracker-ref");
|
||||
addOptionalPropertyReference(builder, "loadBalancingPolicy", element, "load-balancing-policy-ref");
|
||||
addOptionalPropertyReference(builder, "nettyOptions", element, "netty-options-ref");
|
||||
addOptionalPropertyReference(builder, "reconnectionPolicy", element, "reconnection-policy-ref");
|
||||
addOptionalPropertyReference(builder, "retryPolicy", element, "retry-policy-ref");
|
||||
addOptionalPropertyReference(builder, "speculativeExecutionPolicy", element, "speculative-execution-policy-ref");
|
||||
addOptionalPropertyReference(builder, "sslOptions", element, "ssl-options-ref");
|
||||
addOptionalPropertyReference(builder, "timestampGenerator", element, "timestamp-generator-ref");
|
||||
|
||||
addOptionalPropertyValue(builder, "clusterName", element, "cluster-name");
|
||||
addOptionalPropertyValue(builder, "contactPoints", element, "contact-points");
|
||||
addOptionalPropertyValue(builder, "compressionType", element, "compression");
|
||||
addOptionalPropertyValue(builder, "jmxReportingEnabled", element, "jmx-reporting-enabled");
|
||||
addOptionalPropertyValue(builder, "maxSchemaAgreementWaitSeconds", element, "max-schema-agreement-wait-seconds");
|
||||
addOptionalPropertyValue(builder, "metricsEnabled", element, "metrics-enabled");
|
||||
addOptionalPropertyValue(builder, "password", element, "password");
|
||||
addOptionalPropertyValue(builder, "port", element, "port");
|
||||
addOptionalPropertyValue(builder, "sslEnabled", element, "ssl-enabled");
|
||||
addOptionalPropertyValue(builder, "username", element, "username");
|
||||
|
||||
parseChildElements(element, parserContext, builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses child elements of cluster.
|
||||
*
|
||||
* @param element {@link Element} to parse.
|
||||
* @param parserContext XML parser context and state.
|
||||
* @param builder parent {@link BeanDefinitionBuilder}.
|
||||
*/
|
||||
protected void parseChildElements(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
ManagedSet<BeanDefinition> keyspaceActionSpecificationBeanDefinitions = new ManagedSet<>();
|
||||
|
||||
List<String> startupScripts = new ArrayList<>();
|
||||
List<String> shutdownScripts = new ArrayList<>();
|
||||
|
||||
BeanDefinitionBuilder poolingOptionsBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(PoolingOptionsFactoryBean.class);
|
||||
|
||||
addOptionalPropertyReference(poolingOptionsBuilder, "initializationExecutor", element,
|
||||
"initialization-executor-ref");
|
||||
|
||||
addOptionalPropertyValue(poolingOptionsBuilder, "heartbeatIntervalSeconds", element, "heartbeat-interval-seconds");
|
||||
addOptionalPropertyValue(poolingOptionsBuilder, "idleTimeoutSeconds", element, "idle-timeout-seconds");
|
||||
addOptionalPropertyValue(poolingOptionsBuilder, "poolTimeoutMilliseconds", element, "pool-timeout-milliseconds");
|
||||
addOptionalPropertyValue(poolingOptionsBuilder, "maxQueueSize", element, "max-queue-size");
|
||||
|
||||
// parse child elements
|
||||
for (Element subElement : DomUtils.getChildElements(element)) {
|
||||
|
||||
String name = subElement.getLocalName();
|
||||
|
||||
if ("keyspace".equals(name)) {
|
||||
keyspaceActionSpecificationBeanDefinitions
|
||||
.add(newKeyspaceActionSpecificationBeanDefinition(subElement, parserContext));
|
||||
} else if ("local-pooling-options".equals(name)) {
|
||||
parseLocalPoolingOptions(subElement, poolingOptionsBuilder);
|
||||
} else if ("remote-pooling-options".equals(name)) {
|
||||
parseRemotePoolingOptions(subElement, poolingOptionsBuilder);
|
||||
} else if ("socket-options".equals(name)) {
|
||||
builder.addPropertyValue("socketOptions", newSocketOptionsBeanDefinition(subElement, parserContext));
|
||||
} else if ("startup-cql".equals(name)) {
|
||||
startupScripts.add(parseScript(subElement));
|
||||
} else if ("shutdown-cql".equals(name)) {
|
||||
shutdownScripts.add(parseScript(subElement));
|
||||
}
|
||||
}
|
||||
|
||||
builder.addPropertyValue("keyspaceActions", keyspaceActionSpecificationBeanDefinitions);
|
||||
builder.addPropertyValue("poolingOptions", getSourceBeanDefinition(poolingOptionsBuilder, parserContext, element));
|
||||
builder.addPropertyValue("startupScripts", startupScripts);
|
||||
builder.addPropertyValue("shutdownScripts", shutdownScripts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link BeanDefinition} for a {@link KeyspaceActionSpecification} object.
|
||||
*
|
||||
* @param element Element being parsed.
|
||||
* @param parserContext XML parser context and state.
|
||||
* @return the {@link BeanDefinition} or {@literal null} if action is not given.
|
||||
*/
|
||||
private BeanDefinition newKeyspaceActionSpecificationBeanDefinition(Element element, ParserContext parserContext) {
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(KeyspaceActionSpecificationFactoryBean.class);
|
||||
|
||||
// add required replication defaults
|
||||
addRequiredPropertyValue(builder, "replicationStrategy", KeyspaceAttributes.DEFAULT_REPLICATION_STRATEGY.name());
|
||||
|
||||
addRequiredPropertyValue(builder, "replicationFactor",
|
||||
String.valueOf(KeyspaceAttributes.DEFAULT_REPLICATION_FACTOR));
|
||||
|
||||
addRequiredPropertyValue(builder, "name", element, "name");
|
||||
addOptionalPropertyValue(builder, "durableWrites", element, "durable-writes", "false");
|
||||
addRequiredPropertyValue(builder, "action", element, "action");
|
||||
|
||||
parseReplication(DomUtils.getChildElementByTagName(element, "replication"), builder);
|
||||
|
||||
return getSourceBeanDefinition(builder, parserContext, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the keyspace replication options and adds them to the supplied {@link BeanDefinitionBuilder}.
|
||||
*
|
||||
* @param element {@link Element} to parse.
|
||||
* @param builder The {@link BeanDefinitionBuilder} to add the replication to
|
||||
*/
|
||||
private void parseReplication(@Nullable Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
ManagedList<String> networkTopologyDataCenters = new ManagedList<>();
|
||||
ManagedList<String> networkTopologyReplicationFactors = new ManagedList<>();
|
||||
|
||||
if (element != null) {
|
||||
addOptionalPropertyValue(builder, "replicationStrategy", element, "class",
|
||||
KeyspaceAttributes.DEFAULT_REPLICATION_STRATEGY.name());
|
||||
|
||||
addOptionalPropertyValue(builder, "replicationFactor", element, "replication-factor",
|
||||
String.valueOf(KeyspaceAttributes.DEFAULT_REPLICATION_FACTOR));
|
||||
|
||||
// DataCenters only apply to NetworkTopologyStrategy
|
||||
for (Element dataCenter : DomUtils.getChildElementsByTagName(element, "data-center")) {
|
||||
networkTopologyDataCenters.add(dataCenter.getAttribute("name"));
|
||||
networkTopologyReplicationFactors.add(dataCenter.getAttribute("replication-factor"));
|
||||
}
|
||||
}
|
||||
|
||||
builder.addPropertyValue("networkTopologyDataCenters", networkTopologyDataCenters);
|
||||
builder.addPropertyValue("networkTopologyReplicationFactors", networkTopologyReplicationFactors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses local pooling options.
|
||||
*
|
||||
* @param element {@link Element} to parse.
|
||||
* @param builder {@link BeanDefinitionBuilder} used to build a {@link PoolingOptions} {@link BeanDefinition}.
|
||||
*/
|
||||
void parseLocalPoolingOptions(Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
addOptionalPropertyValue(builder, "localCoreConnections", element, "core-connections", null);
|
||||
addOptionalPropertyValue(builder, "localMaxConnections", element, "max-connections", null);
|
||||
addOptionalPropertyValue(builder, "localMaxSimultaneousRequests", element, "max-simultaneous-requests", null);
|
||||
addOptionalPropertyValue(builder, "localMinSimultaneousRequests", element, "min-simultaneous-requests", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses remote pooling options.
|
||||
*
|
||||
* @param element {@link Element} to parse.
|
||||
* @param builder {@link BeanDefinitionBuilder} used to build a {@link PoolingOptions} {@link BeanDefinition}.
|
||||
*/
|
||||
void parseRemotePoolingOptions(Element element, BeanDefinitionBuilder builder) {
|
||||
|
||||
addOptionalPropertyValue(builder, "remoteCoreConnections", element, "core-connections", null);
|
||||
addOptionalPropertyValue(builder, "remoteMaxConnections", element, "max-connections", null);
|
||||
addOptionalPropertyValue(builder, "remoteMaxSimultaneousRequests", element, "max-simultaneous-requests", null);
|
||||
addOptionalPropertyValue(builder, "remoteMinSimultaneousRequests", element, "min-simultaneous-requests", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CQL script {@link Element}s.
|
||||
*
|
||||
* @param element {@link Element} to parse.
|
||||
* @return return the contents of the {@link Element}, which should contain the CQL script.
|
||||
*/
|
||||
String parseScript(Element element) {
|
||||
return element.getTextContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link BeanDefinition} for a {@link SocketOptions} object.
|
||||
*
|
||||
* @param element {@link Element} to parse.
|
||||
* @param parserContext XML parser context and state.
|
||||
* @return {@link BeanDefinition} for {@link SocketOptionsFactoryBean}.
|
||||
*/
|
||||
BeanDefinition newSocketOptionsBeanDefinition(Element element, ParserContext parserContext) {
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SocketOptionsFactoryBean.class);
|
||||
|
||||
addOptionalPropertyValue(builder, "connectTimeoutMillis", element, "connect-timeout-millis");
|
||||
addOptionalPropertyValue(builder, "keepAlive", element, "keep-alive");
|
||||
addOptionalPropertyValue(builder, "readTimeoutMillis", element, "read-timeout-millis");
|
||||
addOptionalPropertyValue(builder, "receiveBufferSize", element, "receive-buffer-size");
|
||||
addOptionalPropertyValue(builder, "reuseAddress", element, "reuse-address");
|
||||
addOptionalPropertyValue(builder, "sendBufferSize", element, "send-buffer-size");
|
||||
addOptionalPropertyValue(builder, "soLinger", element, "so-linger");
|
||||
addOptionalPropertyValue(builder, "tcpNoDelay", element, "tcp-no-delay");
|
||||
|
||||
return getSourceBeanDefinition(builder, parserContext, element);
|
||||
}
|
||||
}
|
||||
@@ -16,31 +16,14 @@
|
||||
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.cassandra.core.cql.CassandraExceptionTranslator;
|
||||
import org.springframework.data.cassandra.core.cql.CqlOperations;
|
||||
import org.springframework.data.cassandra.core.cql.CqlTemplate;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
|
||||
/**
|
||||
* Factory for creating and configuring a Cassandra {@link Session}, which is a thread-safe singleton. As such, it is
|
||||
* sufficient to have one {@link Session} per application and keyspace.
|
||||
* Factory for creating and configuring a Cassandra {@link CqlSession}, which is a thread-safe singleton. As such, it is
|
||||
* sufficient to have one {@link CqlSession} per application and keyspace.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
@@ -52,216 +35,9 @@ import com.datastax.driver.core.Session;
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator
|
||||
* @see CqlTemplate
|
||||
* @see CassandraExceptionTranslator
|
||||
* @see com.datastax.driver.core.Cluster
|
||||
* @see com.datastax.driver.core.Session
|
||||
* @deprecated since 3.0, use {@link CqlSessionFactoryBean} directly.
|
||||
*/
|
||||
public class CassandraCqlSessionFactoryBean
|
||||
implements FactoryBean<Session>, InitializingBean, DisposableBean, PersistenceExceptionTranslator {
|
||||
@Deprecated
|
||||
public class CassandraCqlSessionFactoryBean extends CqlSessionFactoryBean {
|
||||
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final PersistenceExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
|
||||
|
||||
private @Nullable Cluster cluster;
|
||||
|
||||
private List<String> startupScripts = Collections.emptyList();
|
||||
|
||||
private List<String> shutdownScripts = Collections.emptyList();
|
||||
|
||||
private @Nullable Session session;
|
||||
|
||||
private @Nullable String keyspaceName;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
this.session = connect(getKeyspaceName());
|
||||
|
||||
executeScripts(getStartupScripts());
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
Session connect(@Nullable String keyspaceName) {
|
||||
|
||||
return StringUtils.hasText(keyspaceName) ? getCluster().connect(keyspaceName) : getCluster().connect();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||
*/
|
||||
@Override
|
||||
public Session getObject() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
@Override
|
||||
public Class<? extends Session> getObjectType() {
|
||||
return this.session != null ? this.session.getClass() : Session.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
||||
*/
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
|
||||
executeScripts(getShutdownScripts());
|
||||
getSession().close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given Cassandra CQL scripts. The {@link Session} must be connected when this method is called.
|
||||
*/
|
||||
protected void executeScripts(List<String> scripts) {
|
||||
|
||||
if (!CollectionUtils.isEmpty(scripts)) {
|
||||
|
||||
CqlOperations template = newCqlOperations(getSession());
|
||||
|
||||
scripts.forEach(script -> {
|
||||
logger.info("executing raw CQL [{}]", script);
|
||||
template.execute(script);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
CqlOperations newCqlOperations(Session session) {
|
||||
return new CqlTemplate(session);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
*/
|
||||
@Override
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException e) {
|
||||
return this.exceptionTranslator.translateExceptionIfPossible(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe operation to determine whether the Cassandra {@link Session} is connected or not.
|
||||
*
|
||||
* @return a boolean value indicating whether the Cassandra {@link Session} is connected.
|
||||
* @see com.datastax.driver.core.Session#isClosed()
|
||||
* @see #getObject()
|
||||
*/
|
||||
public boolean isConnected() {
|
||||
|
||||
Session session = getObject();
|
||||
|
||||
return !(session == null || session.isClosed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a reference to the Cassandra {@link Cluster} to use.
|
||||
*
|
||||
* @param cluster a reference to the Cassandra {@link Cluster} used by this application.
|
||||
* @throws IllegalArgumentException if the {@link Cluster} reference is null.
|
||||
* @see com.datastax.driver.core.Cluster
|
||||
* @see #getCluster()
|
||||
*/
|
||||
public void setCluster(Cluster cluster) {
|
||||
|
||||
Assert.notNull(cluster, "Cluster must not be null");
|
||||
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the configured Cassandra {@link Cluster} used by this application.
|
||||
*
|
||||
* @return a reference to the configured Cassandra {@link Cluster}.
|
||||
* @throws IllegalStateException if the reference to the {@link Cluster} was not properly initialized.
|
||||
* @see com.datastax.driver.core.Cluster
|
||||
* @see #setCluster(Cluster)
|
||||
*/
|
||||
protected Cluster getCluster() {
|
||||
|
||||
Assert.state(this.cluster != null, "Cluster was not properly initialized");
|
||||
|
||||
return this.cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the Cassandra Keyspace to connect to. Passing {@literal null}, an empty String, or whitespace will
|
||||
* cause the Cassandra System Keyspace to be used.
|
||||
*
|
||||
* @param keyspaceName a String indicating the name of the Keyspace in which to connect.
|
||||
* @see #getKeyspaceName()
|
||||
*/
|
||||
public void setKeyspaceName(@Nullable String keyspaceName) {
|
||||
this.keyspaceName = keyspaceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the Cassandra Keyspace to connect to.
|
||||
*
|
||||
* @return the name of the Cassandra Keyspace to connect to as a String.
|
||||
* @see #setKeyspaceName(String)
|
||||
*/
|
||||
@Nullable
|
||||
protected String getKeyspaceName() {
|
||||
return this.keyspaceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the connected Cassandra {@link Session}.
|
||||
*
|
||||
* @return a reference to the connected Cassandra {@link Session}.
|
||||
* @throws IllegalStateException if the Cassandra {@link Session} was not properly initialized.
|
||||
* @see com.datastax.driver.core.Session
|
||||
*/
|
||||
protected Session getSession() {
|
||||
|
||||
Session session = getObject();
|
||||
|
||||
Assert.state(session != null, "Session was not properly initialized");
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets CQL scripts to be executed immediately after the session is connected.
|
||||
*/
|
||||
public void setStartupScripts(@Nullable List<String> scripts) {
|
||||
this.startupScripts = (scripts != null ? new ArrayList<>(scripts) : Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable list of startup scripts.
|
||||
*/
|
||||
public List<String> getStartupScripts() {
|
||||
return Collections.unmodifiableList(this.startupScripts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets CQL scripts to be executed immediately before the session is shutdown.
|
||||
*/
|
||||
public void setShutdownScripts(@Nullable List<String> scripts) {
|
||||
this.shutdownScripts = scripts != null ? new ArrayList<>(scripts) : Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable list of shutdown scripts.
|
||||
*/
|
||||
public List<String> getShutdownScripts() {
|
||||
return Collections.unmodifiableList(this.shutdownScripts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import static org.springframework.data.cassandra.config.ParsingUtils.*;
|
||||
|
||||
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.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
|
||||
/**
|
||||
* Parser for <session> definitions.
|
||||
*
|
||||
* @author David Webb
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class CassandraCqlSessionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return CassandraCqlSessionFactoryBean.class;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
|
||||
*/
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||
throws BeanDefinitionStoreException {
|
||||
|
||||
String id = super.resolveId(element, definition, parserContext);
|
||||
|
||||
return StringUtils.hasText(id) ? id : DefaultCqlBeanNames.SESSION;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
|
||||
*/
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
setDefaultProperties(builder);
|
||||
|
||||
parseSessionAttributes(element, parserContext, builder);
|
||||
parseSessionChildElements(element, parserContext, builder);
|
||||
}
|
||||
|
||||
protected void setDefaultProperties(BeanDefinitionBuilder builder) {
|
||||
addRequiredPropertyReference(builder, "cluster", DefaultCqlBeanNames.CLUSTER);
|
||||
}
|
||||
|
||||
private void parseSessionAttributes(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
NamedNodeMap attributes = element.getAttributes();
|
||||
int length = attributes.getLength();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
||||
Attr attribute = (Attr) attributes.item(i);
|
||||
if ("id".equals(attribute.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = attribute.getName();
|
||||
|
||||
if ("keyspace-name".equals(name)) {
|
||||
addRequiredPropertyValue(builder, "keyspaceName", attribute);
|
||||
} else if ("cluster-ref".equals(name)) {
|
||||
addOptionalPropertyReference(builder, "cluster", attribute, DefaultCqlBeanNames.CLUSTER);
|
||||
} else {
|
||||
parseUnhandledSessionElementAttribute(attribute, parserContext, builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseSessionChildElements(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
for (Element child : DomUtils.getChildElements(element)) {
|
||||
|
||||
if ("startup-cql".equals(child.getLocalName())) {
|
||||
builder.addPropertyValue("startupScripts", DomUtils.getTextValue(child));
|
||||
} else if ("shutdown-cql".equals(child.getLocalName())) {
|
||||
builder.addPropertyValue("shutdownScripts", DomUtils.getTextValue(child));
|
||||
} else {
|
||||
throw new IllegalStateException(String.format("encountered unhandled element [%s]", child.getLocalName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given session element attribute. This method is intended to be overridden by subclasses so that any
|
||||
* attributes not known to this class can be properly parsed. The default implementation throws
|
||||
* {@link IllegalStateException}.
|
||||
*/
|
||||
protected void parseUnhandledSessionElementAttribute(Attr attribute, ParserContext parserContext,
|
||||
BeanDefinitionBuilder builder) {
|
||||
|
||||
throw new IllegalStateException(
|
||||
String.format("encountered unhandled session element attribute [%s]", attribute.getName()));
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
|
||||
/**
|
||||
* Factory for configuring a {@link CqlTemplate}.
|
||||
@@ -73,13 +73,13 @@ public class CassandraCqlTemplateFactoryBean implements FactoryBean<CqlTemplate>
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Cassandra {@link Session} to use. The {@link CqlTemplate} will use the logged keyspace of the underlying
|
||||
* {@link Session}. Don't change the keyspace using CQL but use multiple {@link Session} and {@link CqlTemplate}
|
||||
* beans.
|
||||
* Sets the Cassandra {@link CqlSession} to use. The {@link CqlTemplate} will use the logged keyspace of the
|
||||
* underlying {@link CqlSession}. Don't change the keyspace using CQL but use multiple {@link CqlSession} and
|
||||
* {@link CqlTemplate} beans.
|
||||
*
|
||||
* @param session must not be {@literal null}.
|
||||
*/
|
||||
public void setSession(Session session) {
|
||||
public void setSession(CqlSession session) {
|
||||
|
||||
Assert.notNull(session, "Session must not be null");
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.data.cassandra.core.convert.MappingCassandraConverter
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.oss.driver.api.core.session.Session;
|
||||
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} that does its best to register any missing Spring Data Cassandra beans that can be
|
||||
@@ -57,9 +57,10 @@ import com.datastax.driver.core.Session;
|
||||
* {@link CassandraMappingContext} definition present, then it will be used in the {@link CassandraMappingContext} bean
|
||||
* definition.
|
||||
* <p/>
|
||||
* It requires that a single {@link Session} or {@link CassandraSessionFactoryBean} definition be present. As described
|
||||
* above, multiple {@link Session} definitions, multiple {@link CassandraSessionFactoryBean} definitions, or both a
|
||||
* {@link Session} and {@link CassandraSessionFactoryBean} will cause an {@link IllegalStateException} to be thrown.
|
||||
* It requires that a single {@link CqlSession} or {@link CassandraSessionFactoryBean} definition be present. As
|
||||
* described above, multiple {@link CqlSession} definitions, multiple {@link CassandraSessionFactoryBean} definitions,
|
||||
* or both a {@link CqlSession} and {@link CassandraSessionFactoryBean} will cause an {@link IllegalStateException} to
|
||||
* be thrown.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
|
||||
@@ -15,15 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import org.springframework.data.cassandra.core.CassandraAdminOperations;
|
||||
import org.springframework.data.cassandra.core.CassandraAdminTemplate;
|
||||
import org.springframework.data.cassandra.core.CassandraPersistentEntitySchemaCreator;
|
||||
import org.springframework.data.cassandra.core.CassandraPersistentEntitySchemaDropper;
|
||||
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Factory to create and configure a Cassandra {@link com.datastax.driver.core.Session} with support for executing CQL
|
||||
* and initializing the database schema (a.k.a. keyspace).
|
||||
@@ -34,155 +25,9 @@ import org.springframework.util.Assert;
|
||||
* @author Mark Paluch
|
||||
* @see com.datastax.driver.core.KeyspaceMetadata
|
||||
* @see com.datastax.driver.core.TableMetadata
|
||||
* @deprecated since 3.0, use {@link CqlSessionFactoryBean} directly.
|
||||
*/
|
||||
public class CassandraSessionFactoryBean extends CassandraCqlSessionFactoryBean {
|
||||
@Deprecated
|
||||
public class CassandraSessionFactoryBean extends CqlSessionFactoryBean {
|
||||
|
||||
protected static final boolean DEFAULT_CREATE_IF_NOT_EXISTS = false;
|
||||
protected static final boolean DEFAULT_DROP_TABLES = false;
|
||||
protected static final boolean DEFAULT_DROP_UNUSED_TABLES = false;
|
||||
|
||||
private @Nullable CassandraAdminOperations admin;
|
||||
|
||||
private @Nullable CassandraConverter converter;
|
||||
|
||||
private SchemaAction schemaAction = SchemaAction.NONE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.cassandra.config.CassandraCqlSessionFactoryBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
Assert.state(this.converter != null, "Converter was not properly initialized");
|
||||
|
||||
super.afterPropertiesSet();
|
||||
|
||||
this.admin = new CassandraAdminTemplate(getSession(), this.converter);
|
||||
|
||||
performSchemaAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the configure {@link SchemaAction} using {@link CassandraMappingContext} metadata.
|
||||
*/
|
||||
protected void performSchemaAction() {
|
||||
|
||||
boolean create = false;
|
||||
boolean drop = DEFAULT_DROP_TABLES;
|
||||
boolean dropUnused = DEFAULT_DROP_UNUSED_TABLES;
|
||||
boolean ifNotExists = DEFAULT_CREATE_IF_NOT_EXISTS;
|
||||
|
||||
switch (this.schemaAction) {
|
||||
case RECREATE_DROP_UNUSED:
|
||||
dropUnused = true;
|
||||
case RECREATE:
|
||||
drop = true;
|
||||
case CREATE_IF_NOT_EXISTS:
|
||||
ifNotExists = SchemaAction.CREATE_IF_NOT_EXISTS.equals(this.schemaAction);
|
||||
case CREATE:
|
||||
create = true;
|
||||
case NONE:
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
|
||||
if (create) {
|
||||
createTables(drop, dropUnused, ifNotExists);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link CassandraConverter} to use. Schema actions will derive table and user type information from the
|
||||
* {@link CassandraMappingContext} inside {@code converter}.
|
||||
*
|
||||
* @param converter must not be {@literal null}.
|
||||
*/
|
||||
public void setConverter(CassandraConverter converter) {
|
||||
|
||||
Assert.notNull(converter, "CassandraConverter must not be null");
|
||||
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link CassandraConverter}.
|
||||
*/
|
||||
@Nullable
|
||||
public CassandraConverter getConverter() {
|
||||
return this.converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link CassandraMappingContext}.
|
||||
*/
|
||||
protected CassandraMappingContext getMappingContext() {
|
||||
|
||||
CassandraConverter converter = getConverter();
|
||||
|
||||
Assert.state(converter != null, "CassandraConverter was not properly initialized");
|
||||
|
||||
return converter.getMappingContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SchemaAction}.
|
||||
*
|
||||
* @param schemaAction must not be {@literal null}.
|
||||
*/
|
||||
public void setSchemaAction(SchemaAction schemaAction) {
|
||||
|
||||
Assert.notNull(schemaAction, "SchemaAction must not be null");
|
||||
|
||||
this.schemaAction = schemaAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link SchemaAction}.
|
||||
*/
|
||||
public SchemaAction getSchemaAction() {
|
||||
return this.schemaAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform schema actions.
|
||||
*
|
||||
* @param drop {@literal true} to drop types/tables.
|
||||
* @param dropUnused {@literal true} to drop unused types/tables (i.e. types/tables not know to be used by
|
||||
* {@link CassandraMappingContext}).
|
||||
* @param ifNotExists {@literal true} to perform creations fail-safe by adding {@code IF NOT EXISTS} to each creation
|
||||
* statement.
|
||||
*/
|
||||
protected void createTables(boolean drop, boolean dropUnused, boolean ifNotExists) {
|
||||
performSchemaActions(drop, dropUnused, ifNotExists);
|
||||
}
|
||||
|
||||
private void performSchemaActions(boolean drop, boolean dropUnused, boolean ifNotExists) {
|
||||
|
||||
CassandraPersistentEntitySchemaCreator schemaCreator = new CassandraPersistentEntitySchemaCreator(
|
||||
getMappingContext(), getCassandraAdminOperations());
|
||||
|
||||
if (drop) {
|
||||
|
||||
CassandraPersistentEntitySchemaDropper schemaDropper = new CassandraPersistentEntitySchemaDropper(
|
||||
getMappingContext(), getCassandraAdminOperations());
|
||||
|
||||
schemaDropper.dropTables(dropUnused);
|
||||
schemaDropper.dropUserTypes(dropUnused);
|
||||
}
|
||||
|
||||
schemaCreator.createUserTypes(ifNotExists);
|
||||
schemaCreator.createTables(ifNotExists);
|
||||
schemaCreator.createIndexes(ifNotExists);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link CassandraAdminOperations}.
|
||||
*/
|
||||
protected CassandraAdminOperations getCassandraAdminOperations() {
|
||||
|
||||
Assert.state(this.admin != null, "CassandraAdminOperations was not properly initialized");
|
||||
|
||||
return this.admin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import static org.springframework.data.cassandra.config.ParsingUtils.*;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Spring Data Cassandra XML namespace parser for the {@code cassandra:session} element.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class CassandraSessionParser extends CassandraCqlSessionParser {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.cassandra.config.xml.CassandraCqlSessionParser#getBeanClass(org.w3c.dom.Element)
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return CassandraSessionFactoryBean.class;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.cassandra.config.xml.CassandraCqlSessionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
|
||||
*/
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
super.doParse(element, parserContext, builder);
|
||||
|
||||
CassandraMappingXmlBeanFactoryPostProcessorRegistrar.ensureRegistration(element, parserContext);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.cassandra.config.xml.CassandraCqlSessionParser#parseUnhandledSessionElementAttribute(org.w3c.dom.Attr, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
|
||||
*/
|
||||
@Override
|
||||
protected void parseUnhandledSessionElementAttribute(Attr attribute, ParserContext parserContext,
|
||||
BeanDefinitionBuilder builder) {
|
||||
|
||||
String name = attribute.getName();
|
||||
|
||||
if ("cassandra-converter-ref".equals(name)) {
|
||||
addOptionalPropertyReference(builder, "converter", attribute, DefaultBeanNames.CONVERTER);
|
||||
} else if ("schema-action".equals(name)) {
|
||||
addOptionalPropertyValue(builder, "schemaAction", attribute, SchemaAction.NONE.name());
|
||||
} else {
|
||||
super.parseUnhandledSessionElementAttribute(attribute, parserContext, builder);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.cassandra.config.xml.CassandraCqlSessionParser#setDefaultProperties(org.springframework.beans.factory.support.BeanDefinitionBuilder)
|
||||
*/
|
||||
@Override
|
||||
protected void setDefaultProperties(BeanDefinitionBuilder builder) {
|
||||
|
||||
super.setDefaultProperties(builder);
|
||||
|
||||
addRequiredPropertyValue(builder, "schemaAction", SchemaAction.NONE.name());
|
||||
addRequiredPropertyReference(builder, "converter", DefaultBeanNames.CONVERTER);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
|
||||
/**
|
||||
* Factory for configuring a {@link CassandraTemplate}.
|
||||
@@ -91,12 +91,12 @@ public class CassandraTemplateFactoryBean implements FactoryBean<CassandraTempla
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Cassandra {@link Session} to use. The {@link CassandraTemplate} will use the logged keyspace of the
|
||||
* underlying {@link Session}. Don't change the keyspace using CQL but use a {@link SessionFactory}.
|
||||
* Sets the Cassandra {@link CqlSession} to use. The {@link CassandraTemplate} will use the logged keyspace of the
|
||||
* underlying {@link CqlSession}. Don't change the keyspace using CQL but use a {@link SessionFactory}.
|
||||
*
|
||||
* @param session must not be {@literal null}.
|
||||
*/
|
||||
public void setSession(Session session) {
|
||||
public void setSession(CqlSession session) {
|
||||
|
||||
Assert.notNull(session, "Session must not be null");
|
||||
|
||||
@@ -105,7 +105,7 @@ public class CassandraTemplateFactoryBean implements FactoryBean<CassandraTempla
|
||||
|
||||
/**
|
||||
* Sets the Cassandra {@link SessionFactory} to use. The {@link CassandraTemplate} will use the logged keyspace of the
|
||||
* underlying {@link Session}. Don't change the keyspace using CQL.
|
||||
* underlying {@link CqlSession}. Don't change the keyspace using CQL.
|
||||
*
|
||||
* @param sessionFactory must not be {@literal null}.
|
||||
* @since 2.0
|
||||
@@ -119,7 +119,8 @@ public class CassandraTemplateFactoryBean implements FactoryBean<CassandraTempla
|
||||
|
||||
/**
|
||||
* Sets the Cassandra {@link CqlOperations} to use. The {@link CassandraTemplate} will use the logged keyspace of the
|
||||
* underlying {@link Session}. Don't change the keyspace using CQL but use {@link #setSessionFactory(SessionFactory)}.
|
||||
* underlying {@link CqlSession}. Don't change the keyspace using CQL but use
|
||||
* {@link #setSessionFactory(SessionFactory)}.
|
||||
*
|
||||
* @param cqlOperations must not be {@literal null}.
|
||||
* @since 2.0
|
||||
|
||||
@@ -54,8 +54,8 @@ import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
|
||||
|
||||
/**
|
||||
* Factory for creating and configuring a Cassandra {@link Session}, which is a thread-safe singleton. As such, it is
|
||||
* sufficient to have one {@link Session} per application and keyspace.
|
||||
* Factory for creating and configuring a Cassandra {@link CqlSession}, which is a thread-safe singleton. As such, it is
|
||||
* sufficient to have one {@link CqlSession} per application and keyspace.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
@@ -83,6 +83,7 @@ public class CqlSessionFactoryBean implements FactoryBean<CqlSession>, Initializ
|
||||
private @Nullable String username;
|
||||
|
||||
private @Nullable String keyspaceName;
|
||||
private @Nullable String localDatacenter;
|
||||
|
||||
private List<KeyspaceActions> keyspaceActions = new ArrayList<>();
|
||||
private Set<KeyspaceActionSpecification> keyspaceSpecifications = new HashSet<>();
|
||||
@@ -101,6 +102,20 @@ public class CqlSessionFactoryBean implements FactoryBean<CqlSession>, Initializ
|
||||
|
||||
private SchemaAction schemaAction = SchemaAction.NONE;
|
||||
|
||||
/**
|
||||
* Null-safe operation to determine whether the Cassandra {@link CqlSession} is connected or not.
|
||||
*
|
||||
* @return a boolean value indicating whether the Cassandra {@link CqlSession} is connected.
|
||||
* @see Session#isClosed()
|
||||
* @see #getObject()
|
||||
*/
|
||||
public boolean isConnected() {
|
||||
|
||||
CqlSession session = getObject();
|
||||
|
||||
return !(session == null || session.isClosed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a comma-delimited string of the contact points (hosts) to connect to. Default is {@code localhost}; see
|
||||
* {@link #DEFAULT_CONTACT_POINTS}.
|
||||
@@ -160,36 +175,6 @@ public class CqlSessionFactoryBean implements FactoryBean<CqlSession>, Initializ
|
||||
return this.keyspaceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe operation to determine whether the Cassandra {@link Session} is connected or not.
|
||||
*
|
||||
* @return a boolean value indicating whether the Cassandra {@link Session} is connected.
|
||||
* @see Session#isClosed()
|
||||
* @see #getObject()
|
||||
*/
|
||||
public boolean isConnected() {
|
||||
|
||||
CqlSession session = getObject();
|
||||
|
||||
return !(session == null || session.isClosed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the connected Cassandra {@link Session}.
|
||||
*
|
||||
* @return a reference to the connected Cassandra {@link Session}.
|
||||
* @throws IllegalStateException if the Cassandra {@link Session} was not properly initialized.
|
||||
* @see Session
|
||||
*/
|
||||
protected CqlSession getSession() {
|
||||
|
||||
CqlSession session = getObject();
|
||||
|
||||
Assert.state(session != null, "Session was not properly initialized");
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link List} of {@link KeyspaceActions}.
|
||||
*/
|
||||
@@ -278,6 +263,31 @@ public class CqlSessionFactoryBean implements FactoryBean<CqlSession>, Initializ
|
||||
return Collections.unmodifiableSet(this.keyspaceSpecifications);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the local datacenter.
|
||||
*
|
||||
* @param localDatacenter a String indicating the name of the local datacenter.
|
||||
*/
|
||||
public void setLocalDatacenter(@Nullable String localDatacenter) {
|
||||
this.localDatacenter = localDatacenter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the connected Cassandra {@link CqlSession}.
|
||||
*
|
||||
* @return a reference to the connected Cassandra {@link CqlSession}.
|
||||
* @throws IllegalStateException if the Cassandra {@link CqlSession} was not properly initialized.
|
||||
* @see Session
|
||||
*/
|
||||
protected CqlSession getSession() {
|
||||
|
||||
CqlSession session = getObject();
|
||||
|
||||
Assert.state(session != null, "Session was not properly initialized");
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets CQL scripts to be executed immediately after the session is connected.
|
||||
*
|
||||
@@ -434,6 +444,10 @@ public class CqlSessionFactoryBean implements FactoryBean<CqlSession>, Initializ
|
||||
builder.withAuthCredentials(this.username, this.password);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(this.localDatacenter)) {
|
||||
builder.withLocalDatacenter(this.localDatacenter);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -553,7 +567,7 @@ public class CqlSessionFactoryBean implements FactoryBean<CqlSession>, Initializ
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given Cassandra CQL scripts. The {@link Session} must be connected when this method is called.
|
||||
* Executes the given Cassandra CQL scripts. The {@link CqlSession} must be connected when this method is called.
|
||||
*/
|
||||
private void executeScripts(Stream<String> scripts, CqlSession session) {
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ class CqlSessionParser extends AbstractSingleBeanDefinitionParser {
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
addOptionalPropertyValue(builder, "keyspaceName", element, "keyspace-name");
|
||||
addOptionalPropertyValue(builder, "localDatacenter", element, "local-datacenter");
|
||||
addOptionalPropertyValue(builder, "contactPoints", element, "contact-points");
|
||||
addOptionalPropertyValue(builder, "password", element, "password");
|
||||
addOptionalPropertyValue(builder, "port", element, "port");
|
||||
|
||||
@@ -23,7 +23,10 @@ package org.springframework.data.cassandra.config;
|
||||
*/
|
||||
public interface DefaultCqlBeanNames {
|
||||
|
||||
String CLUSTER = "cassandraCluster";
|
||||
/**
|
||||
* @deprecated since 3.0. Cassandra driver 4 no longer provides a {@code Cluster} type.
|
||||
*/
|
||||
@Deprecated String CLUSTER = "cassandraCluster";
|
||||
String SESSION = "cassandraSession";
|
||||
String SESSION_FACTORY = "cassandraSessionFactory";
|
||||
String TEMPLATE = "cqlTemplate";
|
||||
|
||||
@@ -33,6 +33,8 @@ import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceOption;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceOption.ReplicationStrategy;
|
||||
import org.springframework.data.cassandra.core.cql.keyspace.Option;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Factory to create {@link CreateKeyspaceSpecification} and {@link DropKeyspaceSpecification}.
|
||||
*
|
||||
@@ -42,7 +44,7 @@ import org.springframework.data.cassandra.core.cql.keyspace.Option;
|
||||
@RequiredArgsConstructor
|
||||
class KeyspaceActionSpecificationFactory {
|
||||
|
||||
private final KeyspaceIdentifier name;
|
||||
private final CqlIdentifier name;
|
||||
|
||||
private final List<DataCenterReplication> replications;
|
||||
|
||||
@@ -60,7 +62,7 @@ class KeyspaceActionSpecificationFactory {
|
||||
* @return the new {@link KeyspaceActionSpecificationFactoryBuilder} for {@code keyspaceName}.
|
||||
*/
|
||||
public static KeyspaceActionSpecificationFactoryBuilder builder(String keyspaceName) {
|
||||
return builder(KeyspaceIdentifier.of(keyspaceName));
|
||||
return builder(CqlIdentifier.fromCql(keyspaceName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,8 +71,22 @@ class KeyspaceActionSpecificationFactory {
|
||||
*
|
||||
* @param keyspaceName must not be {@literal null} or empty.
|
||||
* @return the new {@link KeyspaceActionSpecificationFactoryBuilder} for {@code keyspaceName}.
|
||||
* @deprecated since 3.0, use {@link #builder(CqlIdentifier)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static KeyspaceActionSpecificationFactoryBuilder builder(KeyspaceIdentifier keyspaceName) {
|
||||
return builder(keyspaceName.toCqlIdentifier());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link KeyspaceActionSpecificationFactoryBuilder} to configure a new
|
||||
* {@link KeyspaceActionSpecificationFactory}.
|
||||
*
|
||||
* @param keyspaceName must not be {@literal null} or empty.
|
||||
* @return the new {@link KeyspaceActionSpecificationFactoryBuilder} for {@code keyspaceName}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static KeyspaceActionSpecificationFactoryBuilder builder(CqlIdentifier keyspaceName) {
|
||||
return new KeyspaceActionSpecificationFactoryBuilder(keyspaceName);
|
||||
}
|
||||
|
||||
@@ -170,7 +186,7 @@ class KeyspaceActionSpecificationFactory {
|
||||
|
||||
static class KeyspaceActionSpecificationFactoryBuilder {
|
||||
|
||||
private final KeyspaceIdentifier name;
|
||||
private final CqlIdentifier name;
|
||||
|
||||
private final List<DataCenterReplication> replications = new ArrayList<>();
|
||||
|
||||
@@ -180,7 +196,7 @@ class KeyspaceActionSpecificationFactory {
|
||||
|
||||
private boolean durableWrites = false;
|
||||
|
||||
private KeyspaceActionSpecificationFactoryBuilder(KeyspaceIdentifier name) {
|
||||
private KeyspaceActionSpecificationFactoryBuilder(CqlIdentifier name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,683 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import static org.springframework.util.ReflectionUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.datastax.driver.core.HostDistance;
|
||||
import com.datastax.driver.core.PoolingOptions;
|
||||
|
||||
/**
|
||||
* Spring {@link FactoryBean} for the Cassandra Java driver {@link PoolingOptions}.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author David Webb
|
||||
* @author Mark Paluch
|
||||
* @author John Blum
|
||||
* @see org.springframework.beans.factory.FactoryBean
|
||||
* @see org.springframework.beans.factory.InitializingBean
|
||||
* @see com.datastax.driver.core.PoolingOptions
|
||||
*/
|
||||
@SuppressWarnings({ "unused", "WeakerAccess" })
|
||||
public class PoolingOptionsFactoryBean implements FactoryBean<PoolingOptions>, InitializingBean {
|
||||
|
||||
private static final PoolingOptions DEFAULT = new PoolingOptions();
|
||||
|
||||
// Compatibility between 3.1.1 and earlier Cassandra driver versions
|
||||
private static final Optional<Method> SET_MAX_QUEUE_SIZE;
|
||||
|
||||
// Compatibility between 3.1.1 and earlier Cassandra driver versions
|
||||
private static final Optional<Method> GET_MAX_QUEUE_SIZE;
|
||||
|
||||
static {
|
||||
SET_MAX_QUEUE_SIZE = Optional
|
||||
.ofNullable(ReflectionUtils.findMethod(PoolingOptions.class, "setMaxQueueSize", int.class));
|
||||
GET_MAX_QUEUE_SIZE = Optional.ofNullable(ReflectionUtils.findMethod(PoolingOptions.class, "getMaxQueueSize"));
|
||||
}
|
||||
|
||||
private @Nullable Executor initializationExecutor;
|
||||
|
||||
private int heartbeatIntervalSeconds;
|
||||
private int idleTimeoutSeconds;
|
||||
private @Nullable Integer localCoreConnections;
|
||||
private @Nullable Integer localMaxConnections;
|
||||
private @Nullable Integer localMaxSimultaneousRequests;
|
||||
private @Nullable Integer localMinSimultaneousRequests;
|
||||
|
||||
// Deprecated since Cassandra Driver 3.1.1
|
||||
private int poolTimeoutMilliseconds;
|
||||
|
||||
// Available since Cassandra Driver 3.1.1
|
||||
private int maxQueueSize;
|
||||
private @Nullable Integer remoteCoreConnections;
|
||||
private @Nullable Integer remoteMaxConnections;
|
||||
private @Nullable Integer remoteMaxSimultaneousRequests;
|
||||
private @Nullable Integer remoteMinSimultaneousRequests;
|
||||
|
||||
private @Nullable PoolingOptions poolingOptions;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
poolingOptions = configureRemoteHostDistancePoolingOptions(
|
||||
configureLocalHostDistancePoolingOptions(newPoolingOptions()));
|
||||
|
||||
if (heartbeatIntervalSeconds != DEFAULT.getHeartbeatIntervalSeconds()) {
|
||||
poolingOptions.setHeartbeatIntervalSeconds(heartbeatIntervalSeconds);
|
||||
}
|
||||
|
||||
if (idleTimeoutSeconds != DEFAULT.getIdleTimeoutSeconds()) {
|
||||
poolingOptions.setIdleTimeoutSeconds(idleTimeoutSeconds);
|
||||
}
|
||||
|
||||
if (initializationExecutor != null) {
|
||||
poolingOptions.setInitializationExecutor(initializationExecutor);
|
||||
}
|
||||
|
||||
if (poolTimeoutMilliseconds != DEFAULT.getPoolTimeoutMillis()) {
|
||||
poolingOptions.setPoolTimeoutMillis(poolTimeoutMilliseconds);
|
||||
}
|
||||
|
||||
if (!isDefaultMaxQueueSize()) {
|
||||
SET_MAX_QUEUE_SIZE.ifPresent(method -> invokeMethod(method, poolingOptions, maxQueueSize));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDefaultMaxQueueSize() {
|
||||
|
||||
return GET_MAX_QUEUE_SIZE.map(method -> {
|
||||
|
||||
Integer defaultMaxQueueSize = (Integer) invokeMethod(method, poolingOptions);
|
||||
return defaultMaxQueueSize != null && defaultMaxQueueSize == maxQueueSize;
|
||||
}).orElse(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.datastax.driver.core.PoolingOptions
|
||||
*/
|
||||
PoolingOptions newPoolingOptions() {
|
||||
return new PoolingOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns a {@link PoolingOptionsFactoryBean.HostDistancePoolingOptions} instance initialized with the
|
||||
* {@link HostDistance#LOCAL}-based {@link PoolingOptions} as configured on this {@link PoolingOptionsFactoryBean}.
|
||||
*
|
||||
* @return {@link PoolingOptionsFactoryBean.HostDistancePoolingOptions} initialized with this
|
||||
* {@link PoolingOptionsFactoryBean}'s {@link HostDistance#LOCAL}-based {@link PoolingOptions}.
|
||||
* @see com.datastax.driver.core.HostDistance#LOCAL
|
||||
* @see com.datastax.driver.core.PoolingOptions
|
||||
* @see PoolingOptionsFactoryBean.HostDistancePoolingOptions
|
||||
* @see PoolingOptionsFactoryBean.LocalHostDistancePoolingOptions
|
||||
*/
|
||||
protected HostDistancePoolingOptions newLocalHostDistancePoolingOptions() {
|
||||
return new LocalHostDistancePoolingOptions(getLocalCoreConnections(), getLocalMaxConnections(),
|
||||
getLocalMaxSimultaneousRequests(), getLocalMinSimultaneousRequests());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns a {@link PoolingOptionsFactoryBean.HostDistancePoolingOptions} instance initialized with the
|
||||
* {@link HostDistance#REMOTE}-based {@link PoolingOptions} as configured on this {@link PoolingOptionsFactoryBean}.
|
||||
*
|
||||
* @return {@link PoolingOptionsFactoryBean.HostDistancePoolingOptions} initialized with this
|
||||
* {@link PoolingOptionsFactoryBean}'s {@link HostDistance#REMOTE}-based {@link PoolingOptions}.
|
||||
* @see com.datastax.driver.core.HostDistance#REMOTE
|
||||
* @see com.datastax.driver.core.PoolingOptions
|
||||
* @see PoolingOptionsFactoryBean.HostDistancePoolingOptions
|
||||
* @see PoolingOptionsFactoryBean.RemoteHostDistancePoolingOptions
|
||||
*/
|
||||
protected HostDistancePoolingOptions newRemoteHostDistancePoolingOptions() {
|
||||
return new RemoteHostDistancePoolingOptions(getRemoteCoreConnections(), getRemoteMaxConnections(),
|
||||
getRemoteMaxSimultaneousRequests(), getRemoteMinSimultaneousRequests());
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link HostDistance#LOCAL} connection settings on the given {@link PoolingOptions}.
|
||||
*
|
||||
* @param poolingOptions the {@link PoolingOptions} to configure.
|
||||
* @return the given {@link PoolingOptions}.
|
||||
* @see com.datastax.driver.core.HostDistance#LOCAL
|
||||
* @see com.datastax.driver.core.PoolingOptions
|
||||
* @see #newLocalHostDistancePoolingOptions()
|
||||
*/
|
||||
protected PoolingOptions configureLocalHostDistancePoolingOptions(PoolingOptions poolingOptions) {
|
||||
return newLocalHostDistancePoolingOptions().configure(poolingOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link HostDistance#REMOTE} connection settings on the given {@link PoolingOptions}.
|
||||
*
|
||||
* @param poolingOptions the {@link PoolingOptions} to configure.
|
||||
* @return the given {@link PoolingOptions}.
|
||||
* @see com.datastax.driver.core.HostDistance#REMOTE
|
||||
* @see com.datastax.driver.core.PoolingOptions
|
||||
* @see #newRemoteHostDistancePoolingOptions()
|
||||
*/
|
||||
protected PoolingOptions configureRemoteHostDistancePoolingOptions(PoolingOptions poolingOptions) {
|
||||
return newRemoteHostDistancePoolingOptions().configure(poolingOptions);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||
*/
|
||||
@Override
|
||||
public PoolingOptions getObject() throws Exception {
|
||||
return poolingOptions;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return (poolingOptions != null ? poolingOptions.getClass() : PoolingOptions.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
||||
*/
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the heart beat interval, after which a message is sent on an idle connection to make sure it's still alive.
|
||||
*
|
||||
* @param heartbeatIntervalSeconds interval in seconds between heartbeat messages to keep idle connections alive.
|
||||
*/
|
||||
public void setHeartbeatIntervalSeconds(int heartbeatIntervalSeconds) {
|
||||
this.heartbeatIntervalSeconds = heartbeatIntervalSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the heart beat interval, after which a message is sent on an idle connection to make sure it's still alive.
|
||||
*
|
||||
* @return the {@code heartbeatIntervalSeconds}.
|
||||
*/
|
||||
public int getHeartbeatIntervalSeconds() {
|
||||
return heartbeatIntervalSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timeout before an idle connection is removed.
|
||||
*
|
||||
* @param idleTimeoutSeconds idle timeout in seconds before a connection is removed.
|
||||
*/
|
||||
public void setIdleTimeoutSeconds(int idleTimeoutSeconds) {
|
||||
this.idleTimeoutSeconds = idleTimeoutSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timeout before an idle connection is removed.
|
||||
*
|
||||
* @return the {@code idleTimeoutSeconds}.
|
||||
*/
|
||||
public int getIdleTimeoutSeconds() {
|
||||
return idleTimeoutSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Executor} to use for connection initialization.
|
||||
*
|
||||
* @param initializationExecutor {@link Executor} used to initialize the connection.
|
||||
*/
|
||||
public void setInitializationExecutor(Executor initializationExecutor) {
|
||||
this.initializationExecutor = initializationExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Executor} to use for connection initialization.
|
||||
*
|
||||
* @return the {@code initializationExecutor}.
|
||||
*/
|
||||
@Nullable
|
||||
public Executor getInitializationExecutor() {
|
||||
return initializationExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timeout when trying to acquire a connection from a host's pool.
|
||||
*
|
||||
* @param poolTimeoutMilliseconds timeout in milliseconds used to acquire a connection from the host's pool.
|
||||
*/
|
||||
public void setPoolTimeoutMilliseconds(int poolTimeoutMilliseconds) {
|
||||
this.poolTimeoutMilliseconds = poolTimeoutMilliseconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the timeout when trying to acquire a connection from a host's pool.
|
||||
*
|
||||
* @return the {@code poolTimeoutMilliseconds}.
|
||||
*/
|
||||
public int getPoolTimeoutMilliseconds() {
|
||||
return poolTimeoutMilliseconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of requests that get enqueued if no connection is available.
|
||||
*
|
||||
* @param maxQueueSize maximum number of requests that get enqueued if no connection is available.
|
||||
*/
|
||||
public void setMaxQueueSize(Integer maxQueueSize) {
|
||||
this.maxQueueSize = maxQueueSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of requests that get enqueued if no connection is available.
|
||||
*
|
||||
* @return the {@code maxQueueSize}.
|
||||
*/
|
||||
public Integer getMaxQueueSize() {
|
||||
return maxQueueSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the core number of connections per host for the {@link HostDistance#LOCAL} scope.
|
||||
*
|
||||
* @param localCoreConnections core number of local connections per host.
|
||||
*/
|
||||
public void setLocalCoreConnections(@Nullable Integer localCoreConnections) {
|
||||
this.localCoreConnections = localCoreConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the core number of connections per host for the {@link HostDistance#LOCAL} scope.
|
||||
*
|
||||
* @return the {@code localCoreConnections).
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getLocalCoreConnections() {
|
||||
return localCoreConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of connections per host for the {@link HostDistance#LOCAL} scope.
|
||||
*
|
||||
* @param localMaxConnections max number of local connections per host.
|
||||
*/
|
||||
public void setLocalMaxConnections(@Nullable Integer localMaxConnections) {
|
||||
this.localMaxConnections = localMaxConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of connections per host for the {@link HostDistance#LOCAL} scope.
|
||||
*
|
||||
* @return the {@code localMaxConnections}.
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getLocalMaxConnections() {
|
||||
return localMaxConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of requests per connection for the {@link HostDistance#LOCAL} scope.
|
||||
*
|
||||
* @param localMaxSimultaneousRequests max number of requests for local connections.
|
||||
*/
|
||||
public void setLocalMaxSimultaneousRequests(@Nullable Integer localMaxSimultaneousRequests) {
|
||||
this.localMaxSimultaneousRequests = localMaxSimultaneousRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of requests per connection for the {@link HostDistance#LOCAL} scope.
|
||||
*
|
||||
* @return the {@code localMaxSimultaneousRequests}.
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getLocalMaxSimultaneousRequests() {
|
||||
return localMaxSimultaneousRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the threshold that triggers the creation of a new connection to a host for the {@link HostDistance#LOCAL}
|
||||
* scope.
|
||||
*
|
||||
* @param localMinSimultaneousRequests threshold triggering the creation of local connections to a host.
|
||||
*/
|
||||
public void setLocalMinSimultaneousRequests(@Nullable Integer localMinSimultaneousRequests) {
|
||||
this.localMinSimultaneousRequests = localMinSimultaneousRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the threshold that triggers the creation of a new connection to a host for the {@link HostDistance#LOCAL}
|
||||
* scope.
|
||||
*
|
||||
* @return the {@code localMinSimultaneousRequests}.
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getLocalMinSimultaneousRequests() {
|
||||
return localMinSimultaneousRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the core number of connections per host for the {@link HostDistance#REMOTE} scope.
|
||||
*
|
||||
* @param remoteCoreConnections core number of remote connections per host.
|
||||
*/
|
||||
public void setRemoteCoreConnections(@Nullable Integer remoteCoreConnections) {
|
||||
this.remoteCoreConnections = remoteCoreConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the core number of connections per host for the {@link HostDistance#REMOTE} scope.
|
||||
*
|
||||
* @return the {@code remoteCoreConnections).
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getRemoteCoreConnections() {
|
||||
return remoteCoreConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of connections per host for the {@link HostDistance#REMOTE} scope.
|
||||
*
|
||||
* @param remoteMaxConnections max number of remote connections per host.
|
||||
*/
|
||||
public void setRemoteMaxConnections(@Nullable Integer remoteMaxConnections) {
|
||||
this.remoteMaxConnections = remoteMaxConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of connections per host for the {@link HostDistance#REMOTE} scope.
|
||||
*
|
||||
* @return the {@code remoteMaxConnections}.
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getRemoteMaxConnections() {
|
||||
return remoteMaxConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of requests per connection for the {@link HostDistance#REMOTE} scope.
|
||||
*
|
||||
* @param remoteMaxSimultaneousRequests max number of requests for local connections.
|
||||
*/
|
||||
public void setRemoteMaxSimultaneousRequests(@Nullable Integer remoteMaxSimultaneousRequests) {
|
||||
this.remoteMaxSimultaneousRequests = remoteMaxSimultaneousRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of requests per connection for the {@link HostDistance#REMOTE} scope.
|
||||
*
|
||||
* @return the {@code remoteMaxSimultaneousRequests}.
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getRemoteMaxSimultaneousRequests() {
|
||||
return remoteMaxSimultaneousRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the threshold that triggers the creation of a new connection to a host for the {@link HostDistance#REMOTE}
|
||||
* scope.
|
||||
*
|
||||
* @param remoteMinSimultaneousRequests threshold triggering the creation of remote connections to a host.
|
||||
*/
|
||||
public void setRemoteMinSimultaneousRequests(@Nullable Integer remoteMinSimultaneousRequests) {
|
||||
this.remoteMinSimultaneousRequests = remoteMinSimultaneousRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the threshold that triggers the creation of a new connection to a host for the {@link HostDistance#REMOTE}
|
||||
* scope.
|
||||
*
|
||||
* @return the {@code remoteMinSimultaneousRequests}.
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getRemoteMinSimultaneousRequests() {
|
||||
return remoteMinSimultaneousRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* The HostDistancePoolingOptions class models the {@link PoolingOptions} state and connection settings for a
|
||||
* particular {@link HostDistance}.
|
||||
*
|
||||
* @see com.datastax.driver.core.HostDistance
|
||||
* @see com.datastax.driver.core.PoolingOptions
|
||||
*/
|
||||
protected static abstract class HostDistancePoolingOptions {
|
||||
|
||||
private final @Nullable Integer coreConnectionsPerHost;
|
||||
private final @Nullable Integer maxConnectionsPerHost;
|
||||
private final @Nullable Integer maxRequestsPerConnection;
|
||||
private final @Nullable Integer newConnectionThreshold;
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link HostDistancePoolingOptions} with {@link PoolingOptions} connection settings
|
||||
* specific to a particular {@link HostDistance}.
|
||||
*
|
||||
* @param coreConnectionsPerHost core number of connections per host.
|
||||
* @param maxConnectionsPerHost maximum number of connections per host.
|
||||
* @param maxRequestsPerConnection maximum number of requests per connection.
|
||||
* @param newConnectionThreshold threshold that triggers the creation of a new connection to a host.
|
||||
*/
|
||||
protected HostDistancePoolingOptions(@Nullable Integer coreConnectionsPerHost,
|
||||
@Nullable Integer maxConnectionsPerHost, @Nullable Integer maxRequestsPerConnection,
|
||||
@Nullable Integer newConnectionThreshold) {
|
||||
|
||||
this.coreConnectionsPerHost = coreConnectionsPerHost;
|
||||
this.maxConnectionsPerHost = maxConnectionsPerHost;
|
||||
this.maxRequestsPerConnection = maxRequestsPerConnection;
|
||||
this.newConnectionThreshold = newConnectionThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link HostDistance} used to configure the specific {@link PoolingOptions} connection settings.
|
||||
*
|
||||
* @return a {@link HostDistance} used to configure the specific {@link PoolingOptions} connection settings.
|
||||
* @see com.datastax.driver.core.HostDistance
|
||||
*/
|
||||
protected abstract HostDistance getHostDistance();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.datastax.driver.core.PoolingOptions#setCoreConnectionsPerHost(HostDistance, int)
|
||||
*/
|
||||
void setCoreConnectionsPerHost(PoolingOptions poolingOptions) {
|
||||
if (coreConnectionsPerHost != null) {
|
||||
poolingOptions.setCoreConnectionsPerHost(getHostDistance(), coreConnectionsPerHost);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the core number of connections per host.
|
||||
*
|
||||
* @return {@code coreConnectionsPerHost}.
|
||||
* @see com.datastax.driver.core.PoolingOptions#getCoreConnectionsPerHost(HostDistance)
|
||||
* @see #getHostDistance()
|
||||
*/
|
||||
@Nullable
|
||||
protected Integer getCoreConnectionsPerHost() {
|
||||
return coreConnectionsPerHost;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.datastax.driver.core.PoolingOptions#setMaxConnectionsPerHost(HostDistance, int)
|
||||
*/
|
||||
void setMaxConnectionsPerHost(PoolingOptions poolingOptions) {
|
||||
if (maxConnectionsPerHost != null) {
|
||||
poolingOptions.setMaxConnectionsPerHost(getHostDistance(), maxConnectionsPerHost);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of connections per host.
|
||||
*
|
||||
* @return {@code maxConnectionsPerHost}.
|
||||
* @see com.datastax.driver.core.PoolingOptions#getMaxConnectionsPerHost(HostDistance)
|
||||
* @see #getHostDistance()
|
||||
*/
|
||||
@Nullable
|
||||
protected Integer getMaxConnectionsPerHost() {
|
||||
return maxConnectionsPerHost;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.datastax.driver.core.PoolingOptions#setMaxRequestsPerConnection(HostDistance, int)
|
||||
*/
|
||||
void setMaxRequestsPerConnection(PoolingOptions poolingOptions) {
|
||||
if (maxRequestsPerConnection != null) {
|
||||
poolingOptions.setMaxRequestsPerConnection(getHostDistance(), maxRequestsPerConnection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of requests per connection.
|
||||
*
|
||||
* @return {@code maxRequestsPerConnection}.
|
||||
* @see com.datastax.driver.core.PoolingOptions#getMaxRequestsPerConnection(HostDistance)
|
||||
* @see #getHostDistance()
|
||||
*/
|
||||
@Nullable
|
||||
protected Integer getMaxRequestsPerConnection() {
|
||||
return maxRequestsPerConnection;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the new min is greater than the current max, set the current max to the new min first.
|
||||
* This is enforced by the DSE Driver so you cannot set a new min/max together if either one falls outside
|
||||
* of the default 25-100 range.
|
||||
*
|
||||
* @see com.datastax.driver.core.PoolingOptions#setNewConnectionThreshold(HostDistance, int)
|
||||
*/
|
||||
void setNewConnectionThreshold(PoolingOptions poolingOptions) {
|
||||
|
||||
if (newConnectionThreshold != null) {
|
||||
int currentNewConnectionThreshold = poolingOptions.getNewConnectionThreshold(getHostDistance());
|
||||
|
||||
if (currentNewConnectionThreshold < newConnectionThreshold) {
|
||||
poolingOptions.setNewConnectionThreshold(getHostDistance(), newConnectionThreshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the threshold that triggers the creation of a new connection to a host.
|
||||
*
|
||||
* @return {@code newConnectionThreshold}.
|
||||
* @see com.datastax.driver.core.PoolingOptions#getNewConnectionThreshold(HostDistance)
|
||||
* @see #getHostDistance()
|
||||
*/
|
||||
@Nullable
|
||||
protected Integer getNewConnectionThreshold() {
|
||||
return newConnectionThreshold;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.datastax.driver.core.PoolingOptions
|
||||
*/
|
||||
PoolingOptions configure(PoolingOptions poolingOptions) {
|
||||
|
||||
// order is important here; max properties must be set first
|
||||
setMaxConnectionsPerHost(poolingOptions);
|
||||
setCoreConnectionsPerHost(poolingOptions);
|
||||
setMaxRequestsPerConnection(poolingOptions);
|
||||
setNewConnectionThreshold(poolingOptions);
|
||||
|
||||
return poolingOptions;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see HostDistancePoolingOptions
|
||||
* @see com.datastax.driver.core.PoolingOptions
|
||||
* @see com.datastax.driver.core.HostDistance#LOCAL
|
||||
*/
|
||||
static class LocalHostDistancePoolingOptions extends HostDistancePoolingOptions {
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link LocalHostDistancePoolingOptions} initialized with {@link PoolingOptions} based
|
||||
* on {@link HostDistance#LOCAL}.
|
||||
*
|
||||
* @param coreConnectionsPerHost core number of connections per host.
|
||||
* @param maxConnectionsPerHost maximum number of connections per host.
|
||||
* @param maxRequestsPerConnection maximum number of requests per connection.
|
||||
* @param newConnectionThreshold threshold that triggers the creation of a new connection to a host.
|
||||
*/
|
||||
LocalHostDistancePoolingOptions(@Nullable Integer coreConnectionsPerHost, @Nullable Integer maxConnectionsPerHost,
|
||||
@Nullable Integer maxRequestsPerConnection, @Nullable Integer newConnectionThreshold) {
|
||||
|
||||
super(coreConnectionsPerHost, maxConnectionsPerHost, maxRequestsPerConnection, newConnectionThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link HostDistance#LOCAL} to configure local-based {@link PoolingOptions} connection settings.
|
||||
*
|
||||
* @return {@link HostDistance#LOCAL} to configure local-based {@link PoolingOptions} connection settings.
|
||||
* @see com.datastax.driver.core.HostDistance#LOCAL
|
||||
*/
|
||||
@Override
|
||||
protected HostDistance getHostDistance() {
|
||||
return HostDistance.LOCAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see HostDistancePoolingOptions
|
||||
* @see com.datastax.driver.core.PoolingOptions
|
||||
* @see com.datastax.driver.core.HostDistance#REMOTE
|
||||
*/
|
||||
static class RemoteHostDistancePoolingOptions extends HostDistancePoolingOptions {
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link RemoteHostDistancePoolingOptions} initialized with {@link PoolingOptions} based
|
||||
* on {@link HostDistance#REMOTE}.
|
||||
*
|
||||
* @param coreConnectionsPerHost core number of connections per host.
|
||||
* @param maxConnectionsPerHost maximum number of connections per host.
|
||||
* @param maxRequestsPerConnection maximum number of requests per connection.
|
||||
* @param newConnectionThreshold threshold that triggers the creation of a new connection to a host.
|
||||
*/
|
||||
RemoteHostDistancePoolingOptions(@Nullable Integer coreConnectionsPerHost, @Nullable Integer maxConnectionsPerHost,
|
||||
@Nullable Integer maxRequestsPerConnection, @Nullable Integer newConnectionThreshold) {
|
||||
|
||||
super(coreConnectionsPerHost, maxConnectionsPerHost, maxRequestsPerConnection, newConnectionThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link HostDistance#REMOTE} to configure remote-based {@link PoolingOptions} connection settings.
|
||||
*
|
||||
* @return {@link HostDistance#REMOTE} to configure remote-based {@link PoolingOptions} connection settings.
|
||||
* @see com.datastax.driver.core.HostDistance#REMOTE
|
||||
*/
|
||||
@Override
|
||||
protected HostDistance getHostDistance() {
|
||||
return HostDistance.REMOTE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,25 +15,25 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.oss.driver.api.core.session.SessionBuilder;
|
||||
|
||||
/**
|
||||
* Configuration callback class to allow a user to apply additional configuration logic to the {@link Cluster.Builder}.
|
||||
* Configuration callback class to allow a user to apply additional configuration logic to the {@link SessionBuilder}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @author Mark Paluch
|
||||
* @since 1.5
|
||||
* @see com.datastax.driver.core.Cluster
|
||||
* @see com.datastax.oss.driver.api.core.CqlSession
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ClusterBuilderConfigurer {
|
||||
public interface SessionBuilderConfigurer {
|
||||
|
||||
/**
|
||||
* Apply addition configuration to the {@link com.datastax.driver.core.Cluster.Builder}.
|
||||
* Apply addition configuration to the {@link SessionBuilder}.
|
||||
*
|
||||
* @param clusterBuilder {@link Cluster.Builder} to configure.
|
||||
* @return the argument to the {@code clusterBuilder} parameter.
|
||||
* @see com.datastax.driver.core.Cluster.Builder
|
||||
* @param sessionBuilder {@link SessionBuilder} to configure.
|
||||
* @return the argument to the {@code sessionBuilder} parameter.
|
||||
* @see SessionBuilder
|
||||
*/
|
||||
Cluster.Builder configure(Cluster.Builder clusterBuilder);
|
||||
SessionBuilder configure(SessionBuilder sessionBuilder);
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
|
||||
/**
|
||||
* Factory to create and configure a Cassandra {@link SessionFactory} with support for executing CQL and initializing
|
||||
@@ -46,7 +46,7 @@ public class SessionFactoryFactoryBean extends AbstractFactoryBean<SessionFactor
|
||||
protected static final boolean DEFAULT_DROP_TABLES = false;
|
||||
protected static final boolean DEFAULT_DROP_UNUSED_TABLES = false;
|
||||
|
||||
private Session session;
|
||||
private CqlSession session;
|
||||
|
||||
private @Nullable KeyspacePopulator keyspacePopulator;
|
||||
|
||||
@@ -57,11 +57,11 @@ public class SessionFactoryFactoryBean extends AbstractFactoryBean<SessionFactor
|
||||
private SchemaAction schemaAction = SchemaAction.NONE;
|
||||
|
||||
/**
|
||||
* Set the {@link Session} to use.
|
||||
* Set the {@link CqlSession} to use.
|
||||
*
|
||||
* @param session must not be {@literal null}.
|
||||
*/
|
||||
public void setSession(Session session) {
|
||||
public void setSession(CqlSession session) {
|
||||
|
||||
Assert.notNull(session, "Session must not be null");
|
||||
|
||||
@@ -74,7 +74,7 @@ public class SessionFactoryFactoryBean extends AbstractFactoryBean<SessionFactor
|
||||
* @param keyspacePopulator the {@link KeyspacePopulator} to use during initialization.
|
||||
* @see #setKeyspaceCleaner
|
||||
*/
|
||||
public void setKeyspacePopulator(KeyspacePopulator keyspacePopulator) {
|
||||
public void setKeyspacePopulator(@Nullable KeyspacePopulator keyspacePopulator) {
|
||||
this.keyspacePopulator = keyspacePopulator;
|
||||
}
|
||||
|
||||
@@ -82,10 +82,10 @@ public class SessionFactoryFactoryBean extends AbstractFactoryBean<SessionFactor
|
||||
* Set the {@link KeyspacePopulator} to execute during the bean destruction phase, cleaning up the keyspace and
|
||||
* leaving it in a known state for others.
|
||||
*
|
||||
* @param keyspaceCleaner the {@link KeyspacePopulator} to use during destruction.
|
||||
* @param keyspaceCleaner the {@link KeyspacePopulator} to use during cleanup.
|
||||
* @see #setKeyspacePopulator
|
||||
*/
|
||||
public void setKeyspaceCleaner(KeyspacePopulator keyspaceCleaner) {
|
||||
public void setKeyspaceCleaner(@Nullable KeyspacePopulator keyspaceCleaner) {
|
||||
this.keyspaceCleaner = keyspaceCleaner;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.config;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import com.datastax.driver.core.SocketOptions;
|
||||
|
||||
/**
|
||||
* Socket Options Factory Bean.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author David Webb
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@SuppressWarnings({ "unused", "WeakerAccess" })
|
||||
public class SocketOptionsFactoryBean implements FactoryBean<SocketOptions>, InitializingBean {
|
||||
|
||||
private @Nullable Integer connectTimeoutMillis;
|
||||
|
||||
private @Nullable Boolean keepAlive;
|
||||
|
||||
private @Nullable Integer readTimeoutMillis;
|
||||
|
||||
private @Nullable Boolean reuseAddress;
|
||||
|
||||
private @Nullable Integer soLinger;
|
||||
|
||||
private @Nullable Boolean tcpNoDelay;
|
||||
|
||||
private @Nullable Integer receiveBufferSize;
|
||||
|
||||
private @Nullable Integer sendBufferSize;
|
||||
|
||||
private @Nullable SocketOptions socketOptions;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||
*/
|
||||
@Override
|
||||
public SocketOptions getObject() throws Exception {
|
||||
return socketOptions;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return SocketOptions.class;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
this.socketOptions = new SocketOptions();
|
||||
|
||||
Optional.ofNullable(this.connectTimeoutMillis).ifPresent(this.socketOptions::setConnectTimeoutMillis);
|
||||
Optional.ofNullable(this.readTimeoutMillis).ifPresent(this.socketOptions::setReadTimeoutMillis);
|
||||
Optional.ofNullable(this.keepAlive).ifPresent(this.socketOptions::setKeepAlive);
|
||||
Optional.ofNullable(this.reuseAddress).ifPresent(this.socketOptions::setReuseAddress);
|
||||
Optional.ofNullable(this.soLinger).ifPresent(this.socketOptions::setSoLinger);
|
||||
Optional.ofNullable(this.tcpNoDelay).ifPresent(this.socketOptions::setTcpNoDelay);
|
||||
Optional.ofNullable(this.receiveBufferSize).ifPresent(this.socketOptions::setReceiveBufferSize);
|
||||
Optional.ofNullable(this.sendBufferSize).ifPresent(this.socketOptions::setSendBufferSize);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean getKeepAlive() {
|
||||
return keepAlive;
|
||||
}
|
||||
|
||||
public void setKeepAlive(@Nullable Boolean keepAlive) {
|
||||
this.keepAlive = keepAlive;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean getReuseAddress() {
|
||||
return reuseAddress;
|
||||
}
|
||||
|
||||
public void setReuseAddress(@Nullable Boolean reuseAddress) {
|
||||
this.reuseAddress = reuseAddress;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getSoLinger() {
|
||||
return soLinger;
|
||||
}
|
||||
|
||||
public void setSoLinger(@Nullable Integer soLinger) {
|
||||
this.soLinger = soLinger;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean getTcpNoDelay() {
|
||||
return tcpNoDelay;
|
||||
}
|
||||
|
||||
public void setTcpNoDelay(@Nullable Boolean tcpNoDelay) {
|
||||
this.tcpNoDelay = tcpNoDelay;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getReceiveBufferSize() {
|
||||
return receiveBufferSize;
|
||||
}
|
||||
|
||||
public void setReceiveBufferSize(@Nullable Integer receiveBufferSize) {
|
||||
this.receiveBufferSize = receiveBufferSize;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getSendBufferSize() {
|
||||
return sendBufferSize;
|
||||
}
|
||||
|
||||
public void setSendBufferSize(@Nullable Integer sendBufferSize) {
|
||||
this.sendBufferSize = sendBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the connectTimeoutMillis.
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getConnectTimeoutMillis() {
|
||||
return connectTimeoutMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param connectTimeoutMillis The connectTimeoutMillis to set.
|
||||
*/
|
||||
public void setConnectTimeoutMillis(@Nullable Integer connectTimeoutMillis) {
|
||||
this.connectTimeoutMillis = connectTimeoutMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the readTimeoutMillis.
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getReadTimeoutMillis() {
|
||||
return readTimeoutMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param readTimeoutMillis The readTimeoutMillis to set.
|
||||
*/
|
||||
public void setReadTimeoutMillis(@Nullable Integer readTimeoutMillis) {
|
||||
this.readTimeoutMillis = readTimeoutMillis;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import org.springframework.data.cassandra.core.query.Update;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
|
||||
/**
|
||||
* Interface specifying a basic set of asynchronous Cassandra operations. Implemented by {@link AsyncCassandraTemplate}.
|
||||
@@ -99,7 +99,7 @@ public interface AsyncCassandraOperations {
|
||||
<T> ListenableFuture<T> selectOne(String cql, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.Statement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.Statement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -110,7 +110,7 @@ public interface AsyncCassandraOperations {
|
||||
* @return the converted results
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
<T> ListenableFuture<List<T>> select(Statement statement, Class<T> entityClass) throws DataAccessException;
|
||||
<T> ListenableFuture<List<T>> select(Statement<?> statement, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a {@code SELECT} query with paging and convert the result set to a {@link Slice} of entities. A sliced
|
||||
@@ -122,7 +122,7 @@ public interface AsyncCassandraOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see CassandraPageRequest
|
||||
*/
|
||||
<T> ListenableFuture<Slice<T>> slice(Statement statement, Class<T> entityClass) throws DataAccessException;
|
||||
<T> ListenableFuture<Slice<T>> slice(Statement<?> statement, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a {@code SELECT} query and convert the resulting items notifying {@link Consumer} for each entity.
|
||||
@@ -134,7 +134,7 @@ public interface AsyncCassandraOperations {
|
||||
* @return the completion handle
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
<T> ListenableFuture<Void> select(Statement statement, Consumer<T> entityConsumer, Class<T> entityClass)
|
||||
<T> ListenableFuture<Void> select(Statement<?> statement, Consumer<T> entityConsumer, Class<T> entityClass)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
@@ -145,7 +145,7 @@ public interface AsyncCassandraOperations {
|
||||
* @return the converted object or {@literal null}.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
<T> ListenableFuture<T> selectOne(Statement statement, Class<T> entityClass) throws DataAccessException;
|
||||
<T> ListenableFuture<T> selectOne(Statement<?> statement, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with org.springframework.data.cassandra.core.query.Query
|
||||
|
||||
@@ -17,9 +17,12 @@ package org.springframework.data.cassandra.core;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -32,19 +35,17 @@ import org.springframework.data.cassandra.SessionFactory;
|
||||
import org.springframework.data.cassandra.core.EntityOperations.AdaptibleEntity;
|
||||
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.core.convert.QueryMapper;
|
||||
import org.springframework.data.cassandra.core.convert.UpdateMapper;
|
||||
import org.springframework.data.cassandra.core.cql.AsyncCqlOperations;
|
||||
import org.springframework.data.cassandra.core.cql.AsyncCqlTemplate;
|
||||
import org.springframework.data.cassandra.core.cql.AsyncSessionCallback;
|
||||
import org.springframework.data.cassandra.core.cql.CassandraAccessor;
|
||||
import org.springframework.data.cassandra.core.cql.CqlExceptionTranslator;
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.cql.CqlProvider;
|
||||
import org.springframework.data.cassandra.core.cql.GuavaListenableFutureAdapter;
|
||||
import org.springframework.data.cassandra.core.cql.QueryOptions;
|
||||
import org.springframework.data.cassandra.core.cql.WriteOptions;
|
||||
import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory;
|
||||
import org.springframework.data.cassandra.core.cql.util.CassandraFutureAdapter;
|
||||
import org.springframework.data.cassandra.core.cql.util.StatementBuilder;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.core.mapping.event.AfterConvertEvent;
|
||||
import org.springframework.data.cassandra.core.mapping.event.AfterDeleteEvent;
|
||||
@@ -65,19 +66,20 @@ import org.springframework.scheduling.annotation.AsyncResult;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import com.datastax.driver.core.RegularStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.SimpleStatement;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
import com.datastax.driver.core.querybuilder.Truncate;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
|
||||
import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
import com.datastax.oss.driver.api.querybuilder.QueryBuilder;
|
||||
import com.datastax.oss.driver.api.querybuilder.delete.Delete;
|
||||
import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert;
|
||||
import com.datastax.oss.driver.api.querybuilder.select.Select;
|
||||
import com.datastax.oss.driver.api.querybuilder.truncate.Truncate;
|
||||
import com.datastax.oss.driver.api.querybuilder.update.Update;
|
||||
|
||||
/**
|
||||
* Primary implementation of {@link AsyncCassandraOperations}. It simplifies the use of asynchronous Cassandra usage and
|
||||
@@ -85,11 +87,11 @@ import com.datastax.driver.core.querybuilder.Update;
|
||||
* initiating iteration over {@link ResultSet} and catching Cassandra exceptions and translating them to the generic,
|
||||
* more informative exception hierarchy defined in the {@code org.springframework.dao} package.
|
||||
* <p>
|
||||
* Can be used within a service implementation via direct instantiation with a {@link Session} reference, or get
|
||||
* Can be used within a service implementation via direct instantiation with a {@link CqlSession} reference, or get
|
||||
* prepared in an application context and given to services as bean reference.
|
||||
* <p>
|
||||
* Note: The {@link Session} should always be configured as a bean in the application context, in the first case given
|
||||
* to the service directly, in the second case to the prepared template.
|
||||
* Note: The {@link CqlSession} should always be configured as a bean in the application context, in the first case
|
||||
* given to the service directly, in the second case to the prepared template.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author John Blum
|
||||
@@ -116,28 +118,28 @@ public class AsyncCassandraTemplate
|
||||
private @Nullable EntityCallbacks entityCallbacks;
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link AsyncCassandraTemplate} initialized with the given {@link Session} and a default
|
||||
* Creates an instance of {@link AsyncCassandraTemplate} initialized with the given {@link CqlSession} and a default
|
||||
* {@link MappingCassandraConverter}.
|
||||
*
|
||||
* @param session {@link Session} used to interact with Cassandra; must not be {@literal null}.
|
||||
* @param session {@link CqlSession} used to interact with Cassandra; must not be {@literal null}.
|
||||
* @see CassandraConverter
|
||||
* @see Session
|
||||
*/
|
||||
public AsyncCassandraTemplate(Session session) {
|
||||
public AsyncCassandraTemplate(CqlSession session) {
|
||||
this(session, newConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link AsyncCassandraTemplate} initialized with the given {@link Session} and
|
||||
* Creates an instance of {@link AsyncCassandraTemplate} initialized with the given {@link CqlSession} and
|
||||
* {@link CassandraConverter}.
|
||||
*
|
||||
* @param session {@link Session} used to interact with Cassandra; must not be {@literal null}.
|
||||
* @param session {@link CqlSession} used to interact with Cassandra; must not be {@literal null}.
|
||||
* @param converter {@link CassandraConverter} used to convert between Java and Cassandra types; must not be
|
||||
* {@literal null}.
|
||||
* @see CassandraConverter
|
||||
* @see Session
|
||||
*/
|
||||
public AsyncCassandraTemplate(Session session, CassandraConverter converter) {
|
||||
public AsyncCassandraTemplate(CqlSession session, CassandraConverter converter) {
|
||||
this(new DefaultSessionFactory(session), converter);
|
||||
}
|
||||
|
||||
@@ -175,7 +177,7 @@ public class AsyncCassandraTemplate
|
||||
this.entityOperations = new EntityOperations(converter.getMappingContext());
|
||||
this.exceptionTranslator = asyncCqlTemplate.getExceptionTranslator();
|
||||
this.projectionFactory = new SpelAwareProxyProjectionFactory();
|
||||
this.statementFactory = new StatementFactory(new QueryMapper(converter), new UpdateMapper(converter));
|
||||
this.statementFactory = new StatementFactory(converter);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -257,7 +259,7 @@ public class AsyncCassandraTemplate
|
||||
* Returns the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
|
||||
*
|
||||
* @return the {@link StatementFactory} used by this template to construct and run Cassandra CQL statements.
|
||||
* @see org.springframework.data.cassandra.core.StatementFactory
|
||||
* @see StatementFactory
|
||||
* @since 2.1
|
||||
*/
|
||||
protected StatementFactory getStatementFactory() {
|
||||
@@ -280,7 +282,7 @@ public class AsyncCassandraTemplate
|
||||
|
||||
Assert.hasText(cql, "CQL must not be empty");
|
||||
|
||||
return select(new SimpleStatement(cql), entityClass);
|
||||
return select(SimpleStatement.newInstance(cql), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -294,7 +296,7 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(entityConsumer, "Entity Consumer must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
return select(new SimpleStatement(cql), entityConsumer, entityClass);
|
||||
return select(SimpleStatement.newInstance(cql), entityConsumer, entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -306,18 +308,18 @@ public class AsyncCassandraTemplate
|
||||
Assert.hasText(cql, "CQL must not be empty");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
return selectOne(new SimpleStatement(cql), entityClass);
|
||||
return selectOne(SimpleStatement.newInstance(cql), entityClass);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.Statement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.Statement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#select(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#select(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<List<T>> select(Statement statement, Class<T> entityClass) {
|
||||
public <T> ListenableFuture<List<T>> select(Statement<?> statement, Class<T> entityClass) {
|
||||
|
||||
Assert.notNull(statement, "Statement must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
@@ -328,10 +330,10 @@ public class AsyncCassandraTemplate
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#select(com.datastax.driver.core.Statement, java.util.function.Consumer, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#select(com.datastax.oss.driver.api.core.cql.Statement, java.util.function.Consumer, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<Void> select(Statement statement, Consumer<T> entityConsumer, Class<T> entityClass)
|
||||
public <T> ListenableFuture<Void> select(Statement<?> statement, Consumer<T> entityConsumer, Class<T> entityClass)
|
||||
throws DataAccessException {
|
||||
|
||||
Assert.notNull(statement, "Statement must not be null");
|
||||
@@ -346,29 +348,29 @@ public class AsyncCassandraTemplate
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#selectOne(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#selectOne(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<T> selectOne(Statement statement, Class<T> entityClass) {
|
||||
public <T> ListenableFuture<T> selectOne(Statement<?> statement, Class<T> entityClass) {
|
||||
return new MappingListenableFutureAdapter<>(select(statement, entityClass),
|
||||
list -> list.isEmpty() ? null : list.get(0));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#slice(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.AsyncCassandraOperations#slice(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<Slice<T>> slice(Statement statement, Class<T> entityClass) {
|
||||
public <T> ListenableFuture<Slice<T>> slice(Statement<?> statement, Class<T> entityClass) {
|
||||
|
||||
Assert.notNull(statement, "Statement must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
ListenableFuture<ResultSet> resultSet = getAsyncCqlOperations().queryForResultSet(statement);
|
||||
ListenableFuture<AsyncResultSet> resultSet = getAsyncCqlOperations().queryForResultSet(statement);
|
||||
|
||||
Function<Row, T> mapper = getMapper(entityClass, entityClass, EntityQueryUtils.getTableName(statement));
|
||||
|
||||
return new MappingListenableFutureAdapter<>(resultSet,
|
||||
rs -> EntityQueryUtils.readSlice(rs, (row, rowNum) -> mapper.apply(row), 0, getEffectiveFetchSize(statement)));
|
||||
rs -> EntityQueryUtils.readSlice(rs, (row, rowNum) -> mapper.apply(row), 0, getEffectivePageSize(statement)));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -384,7 +386,7 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(query, "Query must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
return select(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)), entityClass);
|
||||
return select(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)).build(), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -398,7 +400,7 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(entityConsumer, "Entity Consumer must not be empty");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
return select(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)), entityConsumer,
|
||||
return select(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)).build(), entityConsumer,
|
||||
entityClass);
|
||||
}
|
||||
|
||||
@@ -411,7 +413,8 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(query, "Query must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
return selectOne(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)), entityClass);
|
||||
return selectOne(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)).build(),
|
||||
entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -423,7 +426,7 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(query, "Query must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
return slice(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)), entityClass);
|
||||
return slice(getStatementFactory().select(query, getRequiredPersistentEntity(entityClass)).build(), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -438,7 +441,7 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
return getAsyncCqlOperations()
|
||||
.execute(getStatementFactory().update(query, update, getRequiredPersistentEntity(entityClass)));
|
||||
.execute(getStatementFactory().update(query, update, getRequiredPersistentEntity(entityClass)).build());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -455,12 +458,13 @@ public class AsyncCassandraTemplate
|
||||
|
||||
private ListenableFuture<Boolean> doDelete(Query query, Class<?> entityClass, CqlIdentifier tableName) {
|
||||
|
||||
RegularStatement delete = getStatementFactory().delete(query, getRequiredPersistentEntity(entityClass), tableName);
|
||||
StatementBuilder<Delete> builder = getStatementFactory().delete(query, getRequiredPersistentEntity(entityClass),
|
||||
tableName);
|
||||
SimpleStatement delete = builder.build();
|
||||
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName));
|
||||
|
||||
ListenableFuture<Boolean> future = getAsyncCqlOperations()
|
||||
.execute(getStatementFactory().delete(query, getRequiredPersistentEntity(entityClass)));
|
||||
ListenableFuture<Boolean> future = getAsyncCqlOperations().execute(delete);
|
||||
|
||||
future.addCallback(success -> maybeEmitEvent(new AfterDeleteEvent<>(delete, entityClass, tableName)), e -> {});
|
||||
|
||||
@@ -479,9 +483,7 @@ public class AsyncCassandraTemplate
|
||||
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
Select select = QueryBuilder.select().countAll().from(getTableName(entityClass).toCql());
|
||||
|
||||
return getAsyncCqlOperations().queryForObject(select, Long.class);
|
||||
return doCount(Query.empty(), entityClass, getTableName(entityClass));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -493,9 +495,17 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(query, "Query must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
RegularStatement count = getStatementFactory().count(query, getRequiredPersistentEntity(entityClass));
|
||||
return doCount(query, entityClass, getTableName(entityClass));
|
||||
}
|
||||
|
||||
ListenableFuture<Long> result = getAsyncCqlOperations().queryForObject(count, Long.class);
|
||||
ListenableFuture<Long> doCount(Query query, Class<?> entityClass, CqlIdentifier tableName) {
|
||||
|
||||
StatementBuilder<com.datastax.oss.driver.api.querybuilder.select.Select> countStatement = getStatementFactory()
|
||||
.count(query, getRequiredPersistentEntity(entityClass), tableName);
|
||||
|
||||
SimpleStatement statement = countStatement.build();
|
||||
|
||||
ListenableFuture<Long> result = getAsyncCqlOperations().queryForObject(statement, Long.class);
|
||||
|
||||
return new MappingListenableFutureAdapter<>(result, it -> it != null ? it : 0L);
|
||||
}
|
||||
@@ -511,12 +521,11 @@ public class AsyncCassandraTemplate
|
||||
|
||||
CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);
|
||||
|
||||
Select select = QueryBuilder.select().from(entity.getTableName().toCql());
|
||||
StatementBuilder<com.datastax.oss.driver.api.querybuilder.select.Select> select = getStatementFactory()
|
||||
.selectOneById(id, (source, sink) -> getConverter().write(source, sink, entity), entity.getTableName());
|
||||
|
||||
getConverter().write(id, select.where(), entity);
|
||||
|
||||
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().queryForResultSet(select),
|
||||
resultSet -> resultSet.iterator().hasNext());
|
||||
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().queryForResultSet(select.build()),
|
||||
resultSet -> resultSet.remaining() > 0);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -528,10 +537,11 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(query, "Query must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
RegularStatement select = getStatementFactory().select(query.limit(1), getRequiredPersistentEntity(entityClass));
|
||||
StatementBuilder<com.datastax.oss.driver.api.querybuilder.select.Select> select = getStatementFactory()
|
||||
.select(query.limit(1), getRequiredPersistentEntity(entityClass), getTableName(entityClass));
|
||||
|
||||
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().queryForResultSet(select),
|
||||
resultSet -> resultSet.iterator().hasNext());
|
||||
return new MappingListenableFutureAdapter<>(getAsyncCqlOperations().queryForResultSet(select.build()),
|
||||
resultSet -> resultSet.remaining() > 0);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -544,15 +554,13 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);
|
||||
|
||||
Select select = QueryBuilder.select().all().from(entity.getTableName().toCql());
|
||||
|
||||
getConverter().write(id, select.where(), entity);
|
||||
|
||||
Function<Row, T> mapper = getMapper(entityClass, entityClass, entity.getTableName());
|
||||
CqlIdentifier tableName = entity.getTableName();
|
||||
StatementBuilder<Select> select = getStatementFactory().selectOneById(id,
|
||||
(source, sink) -> getConverter().write(source, sink, entity), tableName);
|
||||
Function<Row, T> mapper = getMapper(entityClass, entityClass, tableName);
|
||||
|
||||
return new MappingListenableFutureAdapter<>(
|
||||
getAsyncCqlOperations().query(select, (row, rowNum) -> mapper.apply(row)),
|
||||
getAsyncCqlOperations().query(select.build(), (row, rowNum) -> mapper.apply(row)),
|
||||
it -> it.isEmpty() ? null : it.get(0));
|
||||
}
|
||||
|
||||
@@ -584,14 +592,14 @@ public class AsyncCassandraTemplate
|
||||
|
||||
T entityToUse = source.isVersionedEntity() ? source.initializeVersionProperty() : entity;
|
||||
|
||||
Insert insert = EntityQueryUtils.createInsertQuery(tableName.toCql(), entityToUse, options, getConverter(),
|
||||
persistentEntity);
|
||||
StatementBuilder<RegularInsert> builder = getStatementFactory().insert(entityToUse, options, persistentEntity,
|
||||
tableName);
|
||||
|
||||
return source.isVersionedEntity() ? doInsertVersioned(insert.ifNotExists(), entityToUse, source, tableName)
|
||||
: doInsert(insert, entityToUse, source, tableName);
|
||||
return source.isVersionedEntity() ? doInsertVersioned(builder.build(), entityToUse, source, tableName)
|
||||
: doInsert(builder.build(), entityToUse, source, tableName);
|
||||
}
|
||||
|
||||
private <T> ListenableFuture<EntityWriteResult<T>> doInsertVersioned(Insert insert, T entity,
|
||||
private <T> ListenableFuture<EntityWriteResult<T>> doInsertVersioned(Statement<?> insert, T entity,
|
||||
AdaptibleEntity<T> source, CqlIdentifier tableName) {
|
||||
|
||||
return executeSave(entity, tableName, insert, result -> {
|
||||
@@ -605,7 +613,7 @@ public class AsyncCassandraTemplate
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private <T> ListenableFuture<EntityWriteResult<T>> doInsert(Insert insert, T entity, AdaptibleEntity<T> source,
|
||||
private <T> ListenableFuture<EntityWriteResult<T>> doInsert(Statement<?> insert, T entity, AdaptibleEntity<T> source,
|
||||
CqlIdentifier tableName) {
|
||||
|
||||
return executeSave(entity, tableName, insert);
|
||||
@@ -645,9 +653,10 @@ public class AsyncCassandraTemplate
|
||||
Number previousVersion = source.getVersion();
|
||||
T toSave = source.incrementVersion();
|
||||
|
||||
Update update = getStatementFactory().update(toSave, options, getConverter(), persistentEntity, tableName);
|
||||
StatementBuilder<Update> update = getStatementFactory().update(toSave, options, persistentEntity, tableName);
|
||||
source.appendVersionCondition(update, previousVersion);
|
||||
|
||||
return executeSave(toSave, tableName, source.appendVersionCondition(update, previousVersion), result -> {
|
||||
return executeSave(toSave, tableName, update.build(), result -> {
|
||||
|
||||
if (!result.wasApplied()) {
|
||||
throw new OptimisticLockingFailureException(
|
||||
@@ -660,9 +669,9 @@ public class AsyncCassandraTemplate
|
||||
private <T> ListenableFuture<EntityWriteResult<T>> doUpdate(T entity, UpdateOptions options, CqlIdentifier tableName,
|
||||
CassandraPersistentEntity<?> persistentEntity) {
|
||||
|
||||
Update update = getStatementFactory().update(entity, options, getConverter(), persistentEntity, tableName);
|
||||
StatementBuilder<Update> update = getStatementFactory().update(entity, options, persistentEntity, tableName);
|
||||
|
||||
return executeSave(entity, tableName, update);
|
||||
return executeSave(entity, tableName, update.build());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -686,16 +695,17 @@ public class AsyncCassandraTemplate
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||
CqlIdentifier tableName = persistentEntity.getTableName();
|
||||
|
||||
Delete delete = getStatementFactory().delete(entity, options, getConverter(), persistentEntity, tableName);
|
||||
|
||||
return source.isVersionedEntity() ? doDeleteVersioned(delete, entity, source, tableName)
|
||||
: doDelete(delete, entity, tableName);
|
||||
return source.isVersionedEntity() ? doDeleteVersioned(entity, options, source, tableName)
|
||||
: doDelete(entity, options, tableName);
|
||||
}
|
||||
|
||||
private ListenableFuture<WriteResult> doDeleteVersioned(Delete delete, Object entity, AdaptibleEntity<Object> source,
|
||||
CqlIdentifier tableName) {
|
||||
private ListenableFuture<WriteResult> doDeleteVersioned(Object entity, QueryOptions options,
|
||||
AdaptibleEntity<Object> source, CqlIdentifier tableName) {
|
||||
|
||||
return executeDelete(entity, tableName, source.appendVersionCondition(delete), result -> {
|
||||
StatementBuilder<Delete> delete = getStatementFactory().delete(entity, options, getConverter(), tableName);
|
||||
source.appendVersionCondition(delete);
|
||||
|
||||
return executeDelete(entity, tableName, delete.build(), result -> {
|
||||
|
||||
if (!result.wasApplied()) {
|
||||
throw new OptimisticLockingFailureException(
|
||||
@@ -705,8 +715,11 @@ public class AsyncCassandraTemplate
|
||||
});
|
||||
}
|
||||
|
||||
private ListenableFuture<WriteResult> doDelete(Delete delete, Object entity, CqlIdentifier tableName) {
|
||||
return executeDelete(entity, tableName, delete, result -> {});
|
||||
private ListenableFuture<WriteResult> doDelete(Object entity, QueryOptions options, CqlIdentifier tableName) {
|
||||
|
||||
StatementBuilder<Delete> delete = getStatementFactory().delete(entity, options, getConverter(), tableName);
|
||||
|
||||
return executeDelete(entity, tableName, delete.build(), result -> {});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -719,10 +732,11 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);
|
||||
|
||||
CqlIdentifier tableName = entity.getTableName();
|
||||
Delete delete = QueryBuilder.delete().from(tableName.toCql());
|
||||
getConverter().write(id, delete.where(), entity);
|
||||
|
||||
StatementBuilder<Delete> builder = getStatementFactory().deleteById(id,
|
||||
(source, sink) -> getConverter().write(source, sink, entity), tableName);
|
||||
SimpleStatement delete = builder.build();
|
||||
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName));
|
||||
|
||||
@@ -741,12 +755,13 @@ public class AsyncCassandraTemplate
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
CqlIdentifier tableName = getTableName(entityClass);
|
||||
Truncate truncate = QueryBuilder.truncate(tableName.toCql());
|
||||
Truncate truncate = QueryBuilder.truncate(tableName);
|
||||
SimpleStatement statement = truncate.build();
|
||||
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(truncate, entityClass, tableName));
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entityClass, tableName));
|
||||
|
||||
ListenableFuture<Boolean> future = getAsyncCqlOperations().execute(truncate);
|
||||
future.addCallback(success -> maybeEmitEvent(new AfterDeleteEvent<>(truncate, entityClass, tableName)), e -> {});
|
||||
ListenableFuture<Boolean> future = getAsyncCqlOperations().execute(statement);
|
||||
future.addCallback(success -> maybeEmitEvent(new AfterDeleteEvent<>(statement, entityClass, tableName)), e -> {});
|
||||
|
||||
return new MappingListenableFutureAdapter<>(future, aBoolean -> null);
|
||||
}
|
||||
@@ -756,22 +771,24 @@ public class AsyncCassandraTemplate
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private <T> ListenableFuture<EntityWriteResult<T>> executeSave(T entity, CqlIdentifier tableName,
|
||||
Statement statement) {
|
||||
Statement<?> statement) {
|
||||
|
||||
return executeSave(entity, tableName, statement, ignore -> {});
|
||||
}
|
||||
|
||||
private <T> ListenableFuture<EntityWriteResult<T>> executeSave(T entity, CqlIdentifier tableName, Statement statement,
|
||||
Consumer<WriteResult> beforeAfterSaveEvent) {
|
||||
private <T> ListenableFuture<EntityWriteResult<T>> executeSave(T entity, CqlIdentifier tableName,
|
||||
Statement<?> statement, Consumer<WriteResult> beforeAfterSaveEvent) {
|
||||
|
||||
maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, statement));
|
||||
T entityToSave = maybeCallBeforeSave(entity, tableName, statement);
|
||||
|
||||
ListenableFuture<ResultSet> result = getAsyncCqlOperations().execute(new AsyncStatementCallback(statement));
|
||||
ListenableFuture<AsyncResultSet> result = getAsyncCqlOperations().execute(new AsyncStatementCallback(statement));
|
||||
|
||||
return new MappingListenableFutureAdapter<>(result, resultSet -> {
|
||||
|
||||
EntityWriteResult<T> writeResult = EntityWriteResult.of(resultSet, entityToSave);
|
||||
EntityWriteResult<T> writeResult = new EntityWriteResult<>(
|
||||
Collections.singletonList(resultSet.getExecutionInfo()), resultSet.wasApplied(), getFirstPage(resultSet),
|
||||
entityToSave);
|
||||
|
||||
beforeAfterSaveEvent.accept(writeResult);
|
||||
|
||||
@@ -781,16 +798,17 @@ public class AsyncCassandraTemplate
|
||||
});
|
||||
}
|
||||
|
||||
private ListenableFuture<WriteResult> executeDelete(Object entity, CqlIdentifier tableName, Statement statement,
|
||||
private ListenableFuture<WriteResult> executeDelete(Object entity, CqlIdentifier tableName, Statement<?> statement,
|
||||
Consumer<WriteResult> resultConsumer) {
|
||||
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entity.getClass(), tableName));
|
||||
|
||||
ListenableFuture<ResultSet> result = getAsyncCqlOperations().execute(new AsyncStatementCallback(statement));
|
||||
ListenableFuture<AsyncResultSet> result = getAsyncCqlOperations().execute(new AsyncStatementCallback(statement));
|
||||
|
||||
return new MappingListenableFutureAdapter<>(result, resultSet -> {
|
||||
|
||||
WriteResult writeResult = WriteResult.of(resultSet);
|
||||
WriteResult writeResult = new WriteResult(Collections.singletonList(resultSet.getExecutionInfo()),
|
||||
resultSet.wasApplied(), getFirstPage(resultSet));
|
||||
|
||||
resultConsumer.accept(writeResult);
|
||||
|
||||
@@ -800,14 +818,18 @@ public class AsyncCassandraTemplate
|
||||
});
|
||||
}
|
||||
|
||||
private int getConfiguredFetchSize(Session session) {
|
||||
return session.getCluster().getConfiguration().getQueryOptions().getFetchSize();
|
||||
private static List<Row> getFirstPage(AsyncResultSet resultSet) {
|
||||
return StreamSupport.stream(resultSet.currentPage().spliterator(), false).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private int getEffectiveFetchSize(Statement statement) {
|
||||
private static int getConfiguredPageSize(CqlSession session) {
|
||||
return session.getContext().getConfig().getDefaultProfile().getInt(DefaultDriverOption.REQUEST_PAGE_SIZE, 5000);
|
||||
}
|
||||
|
||||
if (statement.getFetchSize() > 0) {
|
||||
return statement.getFetchSize();
|
||||
private int getEffectivePageSize(Statement<?> statement) {
|
||||
|
||||
if (statement.getPageSize() > 0) {
|
||||
return statement.getPageSize();
|
||||
}
|
||||
|
||||
if (getAsyncCqlOperations() instanceof CassandraAccessor) {
|
||||
@@ -820,7 +842,7 @@ public class AsyncCassandraTemplate
|
||||
}
|
||||
|
||||
return getAsyncCqlOperations()
|
||||
.execute((AsyncSessionCallback<Integer>) session -> AsyncResult.forValue(getConfiguredFetchSize(session)))
|
||||
.execute((AsyncSessionCallback<Integer>) session -> AsyncResult.forValue(getConfiguredPageSize(session)))
|
||||
.completable().join();
|
||||
}
|
||||
|
||||
@@ -831,7 +853,7 @@ public class AsyncCassandraTemplate
|
||||
|
||||
return row -> {
|
||||
|
||||
maybeEmitEvent(new AfterLoadEvent(row, targetType, tableName));
|
||||
maybeEmitEvent(new AfterLoadEvent<>(row, targetType, tableName));
|
||||
|
||||
Object source = getConverter().read(typeToRead, row);
|
||||
|
||||
@@ -874,7 +896,7 @@ public class AsyncCassandraTemplate
|
||||
return object;
|
||||
}
|
||||
|
||||
protected <T> T maybeCallBeforeSave(T object, CqlIdentifier tableName, Statement statement) {
|
||||
protected <T> T maybeCallBeforeSave(T object, CqlIdentifier tableName, Statement<?> statement) {
|
||||
|
||||
if (null != entityCallbacks) {
|
||||
return (T) entityCallbacks.callback(BeforeSaveCallback.class, object, tableName, statement);
|
||||
@@ -903,11 +925,11 @@ public class AsyncCassandraTemplate
|
||||
}
|
||||
|
||||
@Value
|
||||
class AsyncStatementCallback implements AsyncSessionCallback<ResultSet>, CqlProvider {
|
||||
class AsyncStatementCallback implements AsyncSessionCallback<AsyncResultSet>, CqlProvider {
|
||||
|
||||
@lombok.NonNull Statement statement;
|
||||
@lombok.NonNull Statement<?> statement;
|
||||
|
||||
AsyncStatementCallback(Statement statement) {
|
||||
AsyncStatementCallback(Statement<?> statement) {
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
@@ -915,10 +937,10 @@ public class AsyncCassandraTemplate
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncSessionCallback#doInSession(com.datastax.driver.core.Session)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<ResultSet> doInSession(Session session) throws DriverException, DataAccessException {
|
||||
return new GuavaListenableFutureAdapter<>(session.executeAsync(this.statement),
|
||||
e -> e instanceof DriverException
|
||||
? exceptionTranslator.translate("AsyncStatementCallback", getCql(), (DriverException) e)
|
||||
public ListenableFuture<AsyncResultSet> doInSession(CqlSession session)
|
||||
throws DriverException, DataAccessException {
|
||||
return new CassandraFutureAdapter<>(session.executeAsync(this.statement),
|
||||
e -> e instanceof DriverException ? exceptionTranslator.translate("AsyncStatementCallback", getCql(), e)
|
||||
: exceptionTranslator.translateExceptionIfPossible(e));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ package org.springframework.data.cassandra.core;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.mapping.Table;
|
||||
|
||||
import com.datastax.driver.core.KeyspaceMetadata;
|
||||
import com.datastax.driver.core.TableMetadata;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata;
|
||||
import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata;
|
||||
|
||||
/**
|
||||
* Operations for managing a Cassandra keyspace.
|
||||
@@ -96,6 +96,17 @@ public interface CassandraAdminOperations extends CassandraOperations {
|
||||
* @param tableName must not be {@literal null}.
|
||||
* @return the {@link TableMetadata} or {@literal null}.
|
||||
*/
|
||||
Optional<TableMetadata> getTableMetadata(String keyspace, CqlIdentifier tableName);
|
||||
default Optional<TableMetadata> getTableMetadata(String keyspace, CqlIdentifier tableName) {
|
||||
return getTableMetadata(CqlIdentifier.fromCql(keyspace), tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup {@link TableMetadata}.
|
||||
*
|
||||
* @param keyspace must not be {@literal null}.
|
||||
* @param tableName must not be {@literal null}.
|
||||
* @return the {@link TableMetadata} or {@literal null}.
|
||||
* @since 3.0
|
||||
*/
|
||||
Optional<TableMetadata> getTableMetadata(CqlIdentifier keyspace, CqlIdentifier tableName);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.util.Optional;
|
||||
|
||||
import org.springframework.data.cassandra.SessionFactory;
|
||||
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.cql.CqlOperations;
|
||||
import org.springframework.data.cassandra.core.cql.SessionCallback;
|
||||
import org.springframework.data.cassandra.core.cql.generator.CreateTableCqlGenerator;
|
||||
@@ -32,9 +31,10 @@ import org.springframework.data.cassandra.core.cql.keyspace.DropUserTypeSpecific
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.KeyspaceMetadata;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.TableMetadata;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata;
|
||||
import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link CassandraAdminOperations}.
|
||||
@@ -54,7 +54,7 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
||||
* @param session must not be {@literal null}.
|
||||
* @since 2.2
|
||||
*/
|
||||
public CassandraAdminTemplate(Session session) {
|
||||
public CassandraAdminTemplate(CqlSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
||||
* @param session must not be {@literal null}.
|
||||
* @param converter must not be {@literal null}.
|
||||
*/
|
||||
public CassandraAdminTemplate(Session session, CassandraConverter converter) {
|
||||
public CassandraAdminTemplate(CqlSession session, CassandraConverter converter) {
|
||||
super(session, converter);
|
||||
}
|
||||
|
||||
@@ -145,16 +145,18 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraAdminOperations#getTableMetadata(java.lang.String, org.springframework.data.cassandra.core.cql.CqlIdentifier)
|
||||
* @see org.springframework.data.cassandra.core.CassandraAdminOperations#getTableMetadata(com.datastax.oss.driver.api.core.CqlIdentifier, com.datastax.oss.driver.api.core.CqlIdentifier)
|
||||
*/
|
||||
@Override
|
||||
public Optional<TableMetadata> getTableMetadata(String keyspace, CqlIdentifier tableName) {
|
||||
public Optional<TableMetadata> getTableMetadata(CqlIdentifier keyspace, CqlIdentifier tableName) {
|
||||
|
||||
Assert.hasText(keyspace, "Keyspace name must not be empty");
|
||||
Assert.notNull(keyspace, "Keyspace name must not be null");
|
||||
Assert.notNull(tableName, "Table name must not be null");
|
||||
|
||||
return Optional.ofNullable(getCqlOperations().execute((SessionCallback<TableMetadata>) session -> session
|
||||
.getCluster().getMetadata().getKeyspace(keyspace).getTable(tableName.toCql())));
|
||||
// noinspection ConstantConditions
|
||||
return getCqlOperations().execute((SessionCallback<Optional<TableMetadata>>) session -> {
|
||||
return session.getMetadata().getKeyspace(keyspace).flatMap(it -> it.getTable(tableName));
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -166,12 +168,9 @@ public class CassandraAdminTemplate extends CassandraTemplate implements Cassand
|
||||
// noinspection ConstantConditions
|
||||
return getCqlOperations().execute((SessionCallback<KeyspaceMetadata>) session -> {
|
||||
|
||||
KeyspaceMetadata keyspaceMetadata = session.getCluster().getMetadata().getKeyspace(session.getLoggedKeyspace());
|
||||
|
||||
Assert.state(keyspaceMetadata != null,
|
||||
String.format("Metadata for keyspace [%s] not available", session.getLoggedKeyspace()));
|
||||
|
||||
return keyspaceMetadata;
|
||||
return session.getKeyspace().flatMap(it -> session.getMetadata().getKeyspace(it)).orElseThrow(() -> {
|
||||
return new IllegalStateException("Metadata for keyspace not available");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,12 +27,10 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.querybuilder.Batch;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
import com.datastax.oss.driver.api.core.cql.BatchStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.BatchStatementBuilder;
|
||||
import com.datastax.oss.driver.api.core.cql.BatchType;
|
||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||
|
||||
/**
|
||||
* Default implementation for {@link CassandraBatchOperations}.
|
||||
@@ -46,7 +44,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
|
||||
|
||||
private final AtomicBoolean executed = new AtomicBoolean();
|
||||
|
||||
private final Batch batch = QueryBuilder.batch();
|
||||
private final BatchStatementBuilder batch = BatchStatement.builder(BatchType.LOGGED);
|
||||
|
||||
private final CassandraConverter converter;
|
||||
|
||||
@@ -111,7 +109,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
|
||||
public WriteResult execute() {
|
||||
|
||||
if (this.executed.compareAndSet(false, true)) {
|
||||
return WriteResult.of(this.operations.getCqlOperations().queryForResultSet(batch));
|
||||
return WriteResult.of(this.operations.getCqlOperations().queryForResultSet(batch.build()));
|
||||
}
|
||||
|
||||
throw new IllegalStateException("This Cassandra Batch was already executed");
|
||||
@@ -125,7 +123,7 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
|
||||
|
||||
assertNotExecuted();
|
||||
|
||||
this.batch.using(QueryBuilder.timestamp(timestamp));
|
||||
this.batch.setQueryTimestamp(timestamp);
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -169,10 +167,10 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
|
||||
BasicCassandraPersistentEntity<?> persistentEntity = mappingContext
|
||||
.getRequiredPersistentEntity(entity.getClass());
|
||||
|
||||
Insert insertQuery = EntityQueryUtils.createInsertQuery(persistentEntity.getTableName().toCql(), entity, options,
|
||||
getConverter(), persistentEntity);
|
||||
SimpleStatement insertQuery = getStatementFactory()
|
||||
.insert(entity, options, persistentEntity, persistentEntity.getTableName()).build();
|
||||
|
||||
this.batch.add(insertQuery);
|
||||
this.batch.addStatement(insertQuery);
|
||||
}
|
||||
|
||||
return this;
|
||||
@@ -214,10 +212,10 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
|
||||
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||
|
||||
Update update = getStatementFactory().update(entity, options, getConverter(), persistentEntity,
|
||||
persistentEntity.getTableName());
|
||||
SimpleStatement update = getStatementFactory()
|
||||
.update(entity, options, persistentEntity, persistentEntity.getTableName()).build();
|
||||
|
||||
this.batch.add(update);
|
||||
this.batch.addStatement(update);
|
||||
}
|
||||
|
||||
return this;
|
||||
@@ -259,10 +257,10 @@ class CassandraBatchTemplate implements CassandraBatchOperations {
|
||||
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||
|
||||
Delete delete = getStatementFactory().delete(entity, options, this.converter, persistentEntity,
|
||||
persistentEntity.getTableName());
|
||||
SimpleStatement delete = getStatementFactory()
|
||||
.delete(entity, options, this.getConverter(), persistentEntity.getTableName()).build();
|
||||
|
||||
this.batch.add(delete);
|
||||
this.batch.addStatement(delete);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.cql.CqlOperations;
|
||||
import org.springframework.data.cassandra.core.cql.QueryOptions;
|
||||
import org.springframework.data.cassandra.core.cql.WriteOptions;
|
||||
@@ -31,7 +30,8 @@ import org.springframework.data.cassandra.core.query.Update;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
|
||||
/**
|
||||
* Interface specifying a basic set of Cassandra operations. Implemented by {@link CassandraTemplate}. Not often used
|
||||
@@ -120,7 +120,7 @@ public interface CassandraOperations extends FluentCassandraOperations {
|
||||
<T> T selectOne(String cql, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.Statement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.Statement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -131,7 +131,7 @@ public interface CassandraOperations extends FluentCassandraOperations {
|
||||
* @return the converted results
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
<T> List<T> select(Statement statement, Class<T> entityClass) throws DataAccessException;
|
||||
<T> List<T> select(Statement<?> statement, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a {@code SELECT} query with paging and convert the result set to a {@link Slice} of entities. A sliced
|
||||
@@ -143,7 +143,7 @@ public interface CassandraOperations extends FluentCassandraOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @since 2.0
|
||||
*/
|
||||
<T> Slice<T> slice(Statement statement, Class<T> entityClass) throws DataAccessException;
|
||||
<T> Slice<T> slice(Statement<?> statement, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a {@code SELECT} query and convert the resulting items to a {@link Iterator} of entities.
|
||||
@@ -157,7 +157,7 @@ public interface CassandraOperations extends FluentCassandraOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @since 1.5
|
||||
*/
|
||||
<T> Stream<T> stream(Statement statement, Class<T> entityClass) throws DataAccessException;
|
||||
<T> Stream<T> stream(Statement<?> statement, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a {@code SELECT} query and convert the resulting item to an entity.
|
||||
@@ -168,7 +168,7 @@ public interface CassandraOperations extends FluentCassandraOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
@Nullable
|
||||
<T> T selectOne(Statement statement, Class<T> entityClass) throws DataAccessException;
|
||||
<T> T selectOne(Statement<?> statement, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with org.springframework.data.cassandra.core.query.Query
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.cql.generator.CreateIndexCqlGenerator;
|
||||
import org.springframework.data.cassandra.core.cql.generator.CreateTableCqlGenerator;
|
||||
import org.springframework.data.cassandra.core.cql.generator.CreateUserTypeCqlGenerator;
|
||||
@@ -39,6 +38,8 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentProper
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Schema creation support for Cassandra based on {@link CassandraMappingContext} and {@link CassandraPersistentEntity}.
|
||||
* This class generates CQL to create user types (UDT) and tables.
|
||||
|
||||
@@ -25,18 +25,20 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import com.datastax.driver.core.AbstractTableMetadata;
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.TupleType;
|
||||
import com.datastax.driver.core.UserType;
|
||||
import com.datastax.driver.core.UserType.Field;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.metadata.schema.RelationMetadata;
|
||||
import com.datastax.oss.driver.api.core.type.DataType;
|
||||
import com.datastax.oss.driver.api.core.type.ListType;
|
||||
import com.datastax.oss.driver.api.core.type.MapType;
|
||||
import com.datastax.oss.driver.api.core.type.SetType;
|
||||
import com.datastax.oss.driver.api.core.type.TupleType;
|
||||
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
||||
|
||||
/**
|
||||
* Schema drop support for Cassandra based on {@link CassandraMappingContext} and {@link CassandraPersistentEntity}.
|
||||
@@ -80,9 +82,10 @@ public class CassandraPersistentEntitySchemaDropper {
|
||||
|
||||
this.cassandraAdminOperations.getKeyspaceMetadata() //
|
||||
.getTables() //
|
||||
.values() //
|
||||
.stream() //
|
||||
.map(AbstractTableMetadata::getName) //
|
||||
.map(CqlIdentifier::of).filter(table -> dropUnused || this.mappingContext.usesTable(table)) //
|
||||
.map(RelationMetadata::getName) //
|
||||
.filter(table -> dropUnused || this.mappingContext.usesTable(table)) //
|
||||
.forEach(this.cassandraAdminOperations::dropTable);
|
||||
}
|
||||
|
||||
@@ -98,7 +101,8 @@ public class CassandraPersistentEntitySchemaDropper {
|
||||
Set<CqlIdentifier> canRecreate = this.mappingContext.getUserDefinedTypeEntities().stream()
|
||||
.map(CassandraPersistentEntity::getTableName).collect(Collectors.toSet());
|
||||
|
||||
Collection<UserType> userTypes = this.cassandraAdminOperations.getKeyspaceMetadata().getUserTypes();
|
||||
Collection<UserDefinedType> userTypes = this.cassandraAdminOperations.getKeyspaceMetadata().getUserDefinedTypes()
|
||||
.values();
|
||||
|
||||
getUserTypesToDrop(userTypes) //
|
||||
.stream() //
|
||||
@@ -112,7 +116,7 @@ public class CassandraPersistentEntitySchemaDropper {
|
||||
*
|
||||
* @return {@link List} of {@link CqlIdentifier}.
|
||||
*/
|
||||
private List<CqlIdentifier> getUserTypesToDrop(Collection<UserType> knownUserTypes) {
|
||||
private List<CqlIdentifier> getUserTypesToDrop(Collection<UserDefinedType> knownUserTypes) {
|
||||
|
||||
List<CqlIdentifier> toDrop = new ArrayList<>();
|
||||
|
||||
@@ -124,9 +128,7 @@ public class CassandraPersistentEntitySchemaDropper {
|
||||
Set<CqlIdentifier> globalSeen = new LinkedHashSet<>();
|
||||
|
||||
knownUserTypes.forEach(userType -> {
|
||||
|
||||
CqlIdentifier typeName = CqlIdentifier.of(userType.getTypeName());
|
||||
toDrop.addAll(dependencyGraph.getDropOrder(typeName, globalSeen::add));
|
||||
toDrop.addAll(dependencyGraph.getDropOrder(userType.getName(), globalSeen::add));
|
||||
});
|
||||
|
||||
return toDrop;
|
||||
@@ -149,7 +151,7 @@ public class CassandraPersistentEntitySchemaDropper {
|
||||
*
|
||||
* @param userType must not be {@literal null.}
|
||||
*/
|
||||
void addUserType(UserType userType) {
|
||||
void addUserType(UserDefinedType userType) {
|
||||
|
||||
Set<CqlIdentifier> seen = new LinkedHashSet<>();
|
||||
visitTypes(userType, seen::add);
|
||||
@@ -170,45 +172,68 @@ public class CassandraPersistentEntitySchemaDropper {
|
||||
* @param userType
|
||||
* @param typeFilter
|
||||
*/
|
||||
private void visitTypes(UserType userType, Predicate<CqlIdentifier> typeFilter) {
|
||||
private void visitTypes(UserDefinedType userType, Predicate<CqlIdentifier> typeFilter) {
|
||||
|
||||
CqlIdentifier typeName = CqlIdentifier.of(userType.getTypeName());
|
||||
CqlIdentifier typeName = userType.getName();
|
||||
|
||||
if (!typeFilter.test(typeName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Field field : userType) {
|
||||
for (DataType fieldType : userType.getFieldTypes()) {
|
||||
|
||||
if (field.getType() instanceof UserType) {
|
||||
if (fieldType instanceof UserDefinedType) {
|
||||
|
||||
addDependency((UserType) field.getType(), typeName, typeFilter);
|
||||
addDependency((UserDefinedType) fieldType, typeName, typeFilter);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
doWithTypeArguments(field.getType(), it -> {
|
||||
doWithTypeArguments(fieldType, it -> {
|
||||
|
||||
if (it instanceof UserType) {
|
||||
addDependency((UserType) it, typeName, typeFilter);
|
||||
if (it instanceof UserDefinedType) {
|
||||
addDependency((UserDefinedType) it, typeName, typeFilter);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void addDependency(UserType userType, CqlIdentifier requiredBy, Predicate<CqlIdentifier> typeFilter) {
|
||||
private void addDependency(UserDefinedType userType, CqlIdentifier requiredBy,
|
||||
Predicate<CqlIdentifier> typeFilter) {
|
||||
|
||||
dependencies.add(CqlIdentifier.of(userType.getTypeName()), requiredBy);
|
||||
dependencies.add(userType.getName(), requiredBy);
|
||||
|
||||
visitTypes(userType, typeFilter);
|
||||
}
|
||||
|
||||
private static void doWithTypeArguments(DataType type, Consumer<DataType> callback) {
|
||||
|
||||
type.getTypeArguments().forEach(nested -> {
|
||||
callback.accept(nested);
|
||||
doWithTypeArguments(nested, callback);
|
||||
});
|
||||
if (type instanceof MapType) {
|
||||
|
||||
MapType mapType = (MapType) type;
|
||||
|
||||
callback.accept(mapType.getKeyType());
|
||||
doWithTypeArguments(mapType.getKeyType(), callback);
|
||||
|
||||
callback.accept(mapType.getValueType());
|
||||
doWithTypeArguments(mapType.getValueType(), callback);
|
||||
}
|
||||
|
||||
if (type instanceof ListType) {
|
||||
|
||||
ListType listType = (ListType) type;
|
||||
|
||||
callback.accept(listType.getElementType());
|
||||
doWithTypeArguments(listType.getElementType(), callback);
|
||||
}
|
||||
|
||||
if (type instanceof SetType) {
|
||||
|
||||
SetType setType = (SetType) type;
|
||||
|
||||
callback.accept(setType.getElementType());
|
||||
doWithTypeArguments(setType.getElementType(), callback);
|
||||
}
|
||||
|
||||
if (type instanceof TupleType) {
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ import org.springframework.data.cassandra.core.convert.MappingCassandraConverter
|
||||
import org.springframework.data.cassandra.core.convert.QueryMapper;
|
||||
import org.springframework.data.cassandra.core.convert.UpdateMapper;
|
||||
import org.springframework.data.cassandra.core.cql.CassandraAccessor;
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.cql.CqlOperations;
|
||||
import org.springframework.data.cassandra.core.cql.CqlProvider;
|
||||
import org.springframework.data.cassandra.core.cql.CqlTemplate;
|
||||
@@ -45,6 +44,7 @@ import org.springframework.data.cassandra.core.cql.QueryOptions;
|
||||
import org.springframework.data.cassandra.core.cql.SessionCallback;
|
||||
import org.springframework.data.cassandra.core.cql.WriteOptions;
|
||||
import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory;
|
||||
import org.springframework.data.cassandra.core.cql.util.StatementBuilder;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.cassandra.core.mapping.event.AfterConvertEvent;
|
||||
@@ -66,19 +66,20 @@ import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.RegularStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.SimpleStatement;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
import com.datastax.driver.core.querybuilder.Truncate;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
|
||||
import com.datastax.oss.driver.api.core.cql.ResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
import com.datastax.oss.driver.api.querybuilder.QueryBuilder;
|
||||
import com.datastax.oss.driver.api.querybuilder.delete.Delete;
|
||||
import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert;
|
||||
import com.datastax.oss.driver.api.querybuilder.select.Select;
|
||||
import com.datastax.oss.driver.api.querybuilder.truncate.Truncate;
|
||||
import com.datastax.oss.driver.api.querybuilder.update.Update;
|
||||
|
||||
/**
|
||||
* Primary implementation of {@link CassandraOperations}. It simplifies the use of Cassandra usage and helps to avoid
|
||||
@@ -86,11 +87,11 @@ import com.datastax.driver.core.querybuilder.Update;
|
||||
* over {@link ResultSet} and catching Cassandra exceptions and translating them to the generic, more informative
|
||||
* exception hierarchy defined in the {@code org.springframework.dao} package.
|
||||
* <p>
|
||||
* Can be used within a service implementation via direct instantiation with a {@link Session} reference, or get
|
||||
* Can be used within a service implementation via direct instantiation with a {@link CqlSession} reference, or get
|
||||
* prepared in an application context and given to services as bean reference.
|
||||
* <p>
|
||||
* Note: The {@link Session} should always be configured as a bean in the application context, in the first case given
|
||||
* to the service directly, in the second case to the prepared template.
|
||||
* Note: The {@link CqlSession} should always be configured as a bean in the application context, in the first case
|
||||
* given to the service directly, in the second case to the prepared template.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author John Blum
|
||||
@@ -117,28 +118,28 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
private final StatementFactory statementFactory;
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link CassandraTemplate} initialized with the given {@link Session} and a default
|
||||
* Creates an instance of {@link CassandraTemplate} initialized with the given {@link CqlSession} and a default
|
||||
* {@link MappingCassandraConverter}.
|
||||
*
|
||||
* @param session {@link Session} used to interact with Cassandra; must not be {@literal null}.
|
||||
* @param session {@link CqlSession} used to interact with Cassandra; must not be {@literal null}.
|
||||
* @see CassandraConverter
|
||||
* @see Session
|
||||
*/
|
||||
public CassandraTemplate(Session session) {
|
||||
public CassandraTemplate(CqlSession session) {
|
||||
this(session, newConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of {@link CassandraTemplate} initialized with the given {@link Session} and
|
||||
* Creates an instance of {@link CassandraTemplate} initialized with the given {@link CqlSession} and
|
||||
* {@link CassandraConverter}.
|
||||
*
|
||||
* @param session {@link Session} used to interact with Cassandra; must not be {@literal null}.
|
||||
* @param session {@link CqlSession} used to interact with Cassandra; must not be {@literal null}.
|
||||
* @param converter {@link CassandraConverter} used to convert between Java and Cassandra types; must not be
|
||||
* {@literal null}.
|
||||
* @see CassandraConverter
|
||||
* @see Session
|
||||
*/
|
||||
public CassandraTemplate(Session session, CassandraConverter converter) {
|
||||
public CassandraTemplate(CqlSession session, CassandraConverter converter) {
|
||||
this(new DefaultSessionFactory(session), converter);
|
||||
}
|
||||
|
||||
@@ -293,7 +294,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
Assert.hasText(cql, "CQL must not be empty");
|
||||
|
||||
return select(new SimpleStatement(cql), entityClass);
|
||||
return select(SimpleStatement.newInstance(cql), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -305,7 +306,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
Assert.hasText(cql, "CQL must not be empty");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
return selectOne(new SimpleStatement(cql), entityClass);
|
||||
return selectOne(SimpleStatement.newInstance(cql), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -317,18 +318,18 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
Assert.hasText(cql, "CQL must not be empty");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
return stream(new SimpleStatement(cql), entityClass);
|
||||
return stream(SimpleStatement.newInstance(cql), entityClass);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.Statement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.Statement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#select(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#select(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> List<T> select(Statement statement, Class<T> entityClass) {
|
||||
public <T> List<T> select(Statement<?> statement, Class<T> entityClass) {
|
||||
|
||||
Assert.notNull(statement, "Statement must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
@@ -339,20 +340,20 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#selectOne(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#selectOne(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> T selectOne(Statement statement, Class<T> entityClass) {
|
||||
public <T> T selectOne(Statement<?> statement, Class<T> entityClass) {
|
||||
|
||||
List<T> result = select(statement, entityClass);
|
||||
return result.isEmpty() ? null : result.get(0);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#slice(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#slice(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> Slice<T> slice(Statement statement, Class<T> entityClass) {
|
||||
public <T> Slice<T> slice(Statement<?> statement, Class<T> entityClass) {
|
||||
|
||||
Assert.notNull(statement, "Statement must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
@@ -362,14 +363,14 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
Function<Row, T> mapper = getMapper(entityClass, entityClass, EntityQueryUtils.getTableName(statement));
|
||||
|
||||
return EntityQueryUtils.readSlice(resultSet, (row, rowNum) -> mapper.apply(row), 0,
|
||||
getEffectiveFetchSize(statement));
|
||||
getEffectivePageSize(statement));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#stream(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#stream(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> Stream<T> stream(Statement statement, Class<T> entityClass) throws DataAccessException {
|
||||
public <T> Stream<T> stream(Statement<?> statement, Class<T> entityClass) throws DataAccessException {
|
||||
|
||||
Assert.notNull(statement, "Statement must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
@@ -398,18 +399,17 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
<T> List<T> doSelect(Query query, Class<?> entityClass, CqlIdentifier tableName, Class<T> returnType) {
|
||||
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entityClass);
|
||||
CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);
|
||||
|
||||
Columns columns = getStatementFactory().computeColumnsForProjection(query.getColumns(), persistentEntity,
|
||||
returnType);
|
||||
Columns columns = getStatementFactory().computeColumnsForProjection(query.getColumns(), entity, returnType);
|
||||
|
||||
Query queryToUse = query.columns(columns);
|
||||
|
||||
RegularStatement select = getStatementFactory().select(queryToUse, persistentEntity, tableName);
|
||||
StatementBuilder<Select> select = getStatementFactory().select(queryToUse, entity, tableName);
|
||||
|
||||
Function<Row, T> mapper = getMapper(entityClass, returnType, tableName);
|
||||
|
||||
return getCqlOperations().query(select, (row, rowNum) -> mapper.apply(row));
|
||||
return getCqlOperations().query(select.build(), (row, rowNum) -> mapper.apply(row));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -432,9 +432,9 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
Assert.notNull(query, "Query must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
RegularStatement select = getStatementFactory().select(query, getRequiredPersistentEntity(entityClass));
|
||||
StatementBuilder<Select> select = getStatementFactory().select(query, getRequiredPersistentEntity(entityClass));
|
||||
|
||||
return slice(select, entityClass);
|
||||
return slice(select.build(), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -451,12 +451,13 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
<T> Stream<T> doStream(Query query, Class<?> entityClass, CqlIdentifier tableName, Class<T> returnType) {
|
||||
|
||||
RegularStatement statement = getStatementFactory().select(query, getRequiredPersistentEntity(entityClass),
|
||||
StatementBuilder<Select> select = getStatementFactory().select(query, getRequiredPersistentEntity(entityClass),
|
||||
tableName);
|
||||
|
||||
ResultSet resultSet = getCqlOperations().queryForResultSet(statement);
|
||||
ResultSet resultSet = getCqlOperations().queryForResultSet(select.build());
|
||||
|
||||
return StreamSupport.stream(resultSet.spliterator(), false).map(getMapper(entityClass, returnType, tableName));
|
||||
Function<Row, T> mapper = getMapper(entityClass, returnType, tableName);
|
||||
return StreamSupport.stream(resultSet.map(mapper).spliterator(), false);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -470,19 +471,20 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
Assert.notNull(update, "Update must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
Statement updateStatement = getStatementFactory().update(query, update, getRequiredPersistentEntity(entityClass));
|
||||
StatementBuilder<Update> updateStatement = getStatementFactory().update(query, update,
|
||||
getRequiredPersistentEntity(entityClass));
|
||||
|
||||
return getCqlOperations().execute(updateStatement);
|
||||
return getCqlOperations().execute(updateStatement.build());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
WriteResult doUpdate(Query query, org.springframework.data.cassandra.core.query.Update update, Class<?> entityClass,
|
||||
CqlIdentifier tableName) {
|
||||
|
||||
RegularStatement updateStatement = getStatementFactory().update(query, update,
|
||||
StatementBuilder<Update> updateStatement = getStatementFactory().update(query, update,
|
||||
getRequiredPersistentEntity(entityClass), tableName);
|
||||
|
||||
return getCqlOperations().execute(new StatementCallback(updateStatement));
|
||||
return getCqlOperations().execute(new StatementCallback(updateStatement.build()));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -502,13 +504,15 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
@Nullable
|
||||
WriteResult doDelete(Query query, Class<?> entityClass, CqlIdentifier tableName) {
|
||||
|
||||
RegularStatement delete = getStatementFactory().delete(query, getRequiredPersistentEntity(entityClass), tableName);
|
||||
StatementBuilder<Delete> delete = getStatementFactory().delete(query, getRequiredPersistentEntity(entityClass),
|
||||
tableName);
|
||||
SimpleStatement statement = delete.build();
|
||||
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName));
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entityClass, tableName));
|
||||
|
||||
WriteResult writeResult = getCqlOperations().execute(new StatementCallback(delete));
|
||||
WriteResult writeResult = getCqlOperations().execute(new StatementCallback(statement));
|
||||
|
||||
maybeEmitEvent(new AfterDeleteEvent<>(delete, entityClass, tableName));
|
||||
maybeEmitEvent(new AfterDeleteEvent<>(statement, entityClass, tableName));
|
||||
|
||||
return writeResult;
|
||||
}
|
||||
@@ -525,11 +529,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
Select select = QueryBuilder.select().countAll().from(getTableName(entityClass).toCql());
|
||||
|
||||
Long count = getCqlOperations().queryForObject(select, Long.class);
|
||||
|
||||
return count != null ? count : 0L;
|
||||
return count(Query.empty(), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -546,10 +546,11 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
long doCount(Query query, Class<?> entityClass, CqlIdentifier tableName) {
|
||||
|
||||
RegularStatement countStatement = getStatementFactory().count(query, getRequiredPersistentEntity(entityClass),
|
||||
tableName);
|
||||
StatementBuilder<Select> countStatement = getStatementFactory().count(query,
|
||||
getRequiredPersistentEntity(entityClass), tableName);
|
||||
|
||||
Long count = getCqlOperations().queryForObject(countStatement, Long.class);
|
||||
SimpleStatement statement = countStatement.build();
|
||||
Long count = getCqlOperations().queryForObject(statement, Long.class);
|
||||
|
||||
return count != null ? count : 0L;
|
||||
}
|
||||
@@ -565,11 +566,10 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);
|
||||
|
||||
Select select = QueryBuilder.select().from(getTableName(entityClass).toCql());
|
||||
StatementBuilder<Select> select = getStatementFactory().selectOneById(id,
|
||||
(source, sink) -> getConverter().write(source, sink, entity), entity.getTableName());
|
||||
|
||||
getConverter().write(id, select.where(), entity);
|
||||
|
||||
return getCqlOperations().queryForResultSet(select).iterator().hasNext();
|
||||
return getCqlOperations().queryForResultSet(select.build()).iterator().hasNext();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -586,10 +586,10 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
boolean doExists(Query query, Class<?> entityClass, CqlIdentifier tableName) {
|
||||
|
||||
RegularStatement select = getStatementFactory().select(query.limit(1), getRequiredPersistentEntity(entityClass),
|
||||
tableName);
|
||||
StatementBuilder<Select> select = getStatementFactory().select(query.limit(1),
|
||||
getRequiredPersistentEntity(entityClass), tableName);
|
||||
|
||||
return getCqlOperations().queryForResultSet(select).iterator().hasNext();
|
||||
return getCqlOperations().queryForResultSet(select.build()).iterator().hasNext();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -601,15 +601,12 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
Assert.notNull(id, "Id must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
CqlIdentifier tableName = getTableName(entityClass);
|
||||
|
||||
Select select = QueryBuilder.select().all().from(tableName.toCql());
|
||||
|
||||
getConverter().write(id, select.where(), getRequiredPersistentEntity(entityClass));
|
||||
|
||||
CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);
|
||||
CqlIdentifier tableName = entity.getTableName();
|
||||
StatementBuilder<Select> select = getStatementFactory().selectOneById(id,
|
||||
(source, sink) -> getConverter().write(source, sink, entity), tableName);
|
||||
Function<Row, T> mapper = getMapper(entityClass, entityClass, tableName);
|
||||
|
||||
List<T> result = getCqlOperations().query(select, (row, rowNum) -> mapper.apply(row));
|
||||
List<T> result = getCqlOperations().query(select.build(), (row, rowNum) -> mapper.apply(row));
|
||||
|
||||
return result.isEmpty() ? null : result.get(0);
|
||||
}
|
||||
@@ -638,18 +635,18 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
AdaptibleEntity<T> source = getEntityOperations().forEntity(maybeCallBeforeConvert(entity, tableName),
|
||||
getConverter().getConversionService());
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||
|
||||
T entityToUse = source.isVersionedEntity() ? source.initializeVersionProperty() : entity;
|
||||
|
||||
Insert insert = EntityQueryUtils.createInsertQuery(tableName.toCql(), entityToUse, options, getConverter(),
|
||||
persistentEntity);
|
||||
StatementBuilder<RegularInsert> builder = getStatementFactory().insert(entityToUse, options,
|
||||
source.getPersistentEntity(), tableName);
|
||||
SimpleStatement insert = builder.build();
|
||||
|
||||
return source.isVersionedEntity() ? doInsertVersioned(insert.ifNotExists(), entityToUse, source, tableName)
|
||||
return source.isVersionedEntity() ? doInsertVersioned(insert, entityToUse, source, tableName)
|
||||
: doInsert(insert, entityToUse, tableName);
|
||||
}
|
||||
|
||||
private <T> EntityWriteResult<T> doInsertVersioned(Insert insert, T entity, AdaptibleEntity<T> source,
|
||||
private <T> EntityWriteResult<T> doInsertVersioned(SimpleStatement insert, T entity, AdaptibleEntity<T> source,
|
||||
CqlIdentifier tableName) {
|
||||
|
||||
return executeSave(entity, tableName, insert, result -> {
|
||||
@@ -662,7 +659,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
});
|
||||
}
|
||||
|
||||
private <T> EntityWriteResult<T> doInsert(Insert insert, T entity, CqlIdentifier tableName) {
|
||||
private <T> EntityWriteResult<T> doInsert(SimpleStatement insert, T entity, CqlIdentifier tableName) {
|
||||
return executeSave(entity, tableName, insert);
|
||||
}
|
||||
|
||||
@@ -701,9 +698,11 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
Number previousVersion = source.getVersion();
|
||||
T toSave = source.incrementVersion();
|
||||
|
||||
Update update = getStatementFactory().update(toSave, options, getConverter(), persistentEntity, tableName);
|
||||
StatementBuilder<Update> builder = getStatementFactory().update(toSave, options, persistentEntity, tableName);
|
||||
source.appendVersionCondition(builder, previousVersion);
|
||||
SimpleStatement update = builder.build();
|
||||
|
||||
return executeSave(toSave, tableName, source.appendVersionCondition(update, previousVersion), result -> {
|
||||
return executeSave(toSave, tableName, update, result -> {
|
||||
|
||||
if (!result.wasApplied()) {
|
||||
throw new OptimisticLockingFailureException(
|
||||
@@ -716,9 +715,9 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
private <T> EntityWriteResult<T> doUpdate(T entity, UpdateOptions options, CqlIdentifier tableName,
|
||||
CassandraPersistentEntity<?> persistentEntity) {
|
||||
|
||||
Update update = getStatementFactory().update(entity, options, getConverter(), persistentEntity, tableName);
|
||||
StatementBuilder<Update> builder = getStatementFactory().update(entity, options, persistentEntity, tableName);
|
||||
|
||||
return executeSave(entity, tableName, update);
|
||||
return executeSave(entity, tableName, builder.build());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -742,16 +741,18 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||
CqlIdentifier tableName = persistentEntity.getTableName();
|
||||
|
||||
Delete delete = getStatementFactory().delete(entity, options, getConverter(), persistentEntity, tableName);
|
||||
StatementBuilder<Delete> builder = getStatementFactory().delete(entity, options, getConverter(), tableName);
|
||||
source.appendVersionCondition(builder);
|
||||
SimpleStatement delete = builder.build();
|
||||
|
||||
return source.isVersionedEntity() ? doDeleteVersioned(delete, entity, source, tableName)
|
||||
: doDelete(delete, entity, tableName);
|
||||
}
|
||||
|
||||
private WriteResult doDeleteVersioned(Delete delete, Object entity, AdaptibleEntity<Object> source,
|
||||
private WriteResult doDeleteVersioned(Statement<?> statement, Object entity, AdaptibleEntity<Object> source,
|
||||
CqlIdentifier tableName) {
|
||||
|
||||
return executeDelete(entity, tableName, source.appendVersionCondition(delete), result -> {
|
||||
return executeDelete(entity, tableName, statement, result -> {
|
||||
|
||||
if (!result.wasApplied()) {
|
||||
throw new OptimisticLockingFailureException(
|
||||
@@ -761,7 +762,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
});
|
||||
}
|
||||
|
||||
private WriteResult doDelete(Delete delete, Object entity, CqlIdentifier tableName) {
|
||||
private WriteResult doDelete(SimpleStatement delete, Object entity, CqlIdentifier tableName) {
|
||||
return executeDelete(entity, tableName, delete, result -> {});
|
||||
}
|
||||
|
||||
@@ -776,15 +777,16 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
|
||||
CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);
|
||||
CqlIdentifier tableName = entity.getTableName();
|
||||
Delete delete = QueryBuilder.delete().from(tableName.toCql());
|
||||
|
||||
getConverter().write(id, delete.where(), entity);
|
||||
StatementBuilder<Delete> delete = getStatementFactory().deleteById(id,
|
||||
(source, sink) -> getConverter().write(source, sink, entity), tableName);
|
||||
SimpleStatement statement = delete.build();
|
||||
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName));
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entityClass, tableName));
|
||||
|
||||
boolean result = getCqlOperations().execute(delete);
|
||||
boolean result = getCqlOperations().execute(statement);
|
||||
|
||||
maybeEmitEvent(new AfterDeleteEvent<>(delete, entityClass, tableName));
|
||||
maybeEmitEvent(new AfterDeleteEvent<>(statement, entityClass, tableName));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -798,13 +800,14 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
CqlIdentifier tableName = getTableName(entityClass);
|
||||
Truncate truncate = QueryBuilder.truncate(tableName.toCql());
|
||||
Truncate truncate = QueryBuilder.truncate(tableName);
|
||||
SimpleStatement statement = truncate.build();
|
||||
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(truncate, entityClass, tableName));
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entityClass, tableName));
|
||||
|
||||
getCqlOperations().execute(truncate);
|
||||
getCqlOperations().execute(statement);
|
||||
|
||||
maybeEmitEvent(new AfterDeleteEvent<>(truncate, entityClass, tableName));
|
||||
maybeEmitEvent(new AfterDeleteEvent<>(statement, entityClass, tableName));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -847,11 +850,11 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
// Implementation hooks and utility methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private <T> EntityWriteResult<T> executeSave(T entity, CqlIdentifier tableName, Statement statement) {
|
||||
private <T> EntityWriteResult<T> executeSave(T entity, CqlIdentifier tableName, Statement<?> statement) {
|
||||
return executeSave(entity, tableName, statement, ignore -> {});
|
||||
}
|
||||
|
||||
private <T> EntityWriteResult<T> executeSave(T entity, CqlIdentifier tableName, Statement statement,
|
||||
private <T> EntityWriteResult<T> executeSave(T entity, CqlIdentifier tableName, Statement<?> statement,
|
||||
Consumer<WriteResult> resultConsumer) {
|
||||
|
||||
maybeEmitEvent(new BeforeSaveEvent<>(entity, tableName, statement));
|
||||
@@ -865,7 +868,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
return EntityWriteResult.of(result, entityToSave);
|
||||
}
|
||||
|
||||
private WriteResult executeDelete(Object entity, CqlIdentifier tableName, Statement statement,
|
||||
private WriteResult executeDelete(Object entity, CqlIdentifier tableName, Statement<?> statement,
|
||||
Consumer<WriteResult> resultConsumer) {
|
||||
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entity.getClass(), tableName));
|
||||
@@ -879,15 +882,15 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
return result;
|
||||
}
|
||||
|
||||
private int getConfiguredFetchSize(Session session) {
|
||||
return session.getCluster().getConfiguration().getQueryOptions().getFetchSize();
|
||||
private int getConfiguredPageSize(CqlSession session) {
|
||||
return session.getContext().getConfig().getDefaultProfile().getInt(DefaultDriverOption.REQUEST_PAGE_SIZE, 5000);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private int getEffectiveFetchSize(Statement statement) {
|
||||
private int getEffectivePageSize(Statement<?> statement) {
|
||||
|
||||
if (statement.getFetchSize() > 0) {
|
||||
return statement.getFetchSize();
|
||||
if (statement.getPageSize() > 0) {
|
||||
return statement.getPageSize();
|
||||
}
|
||||
|
||||
if (getCqlOperations() instanceof CassandraAccessor) {
|
||||
@@ -899,7 +902,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
}
|
||||
}
|
||||
|
||||
return getCqlOperations().execute(this::getConfiguredFetchSize);
|
||||
return getCqlOperations().execute(this::getConfiguredPageSize);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -952,7 +955,7 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
return object;
|
||||
}
|
||||
|
||||
protected <T> T maybeCallBeforeSave(T object, CqlIdentifier tableName, Statement statement) {
|
||||
protected <T> T maybeCallBeforeSave(T object, CqlIdentifier tableName, Statement<?> statement) {
|
||||
|
||||
if (null != entityCallbacks) {
|
||||
return (T) entityCallbacks.callback(BeforeSaveCallback.class, object, tableName, statement);
|
||||
@@ -964,13 +967,13 @@ public class CassandraTemplate implements CassandraOperations, ApplicationEventP
|
||||
@Value
|
||||
static class StatementCallback implements SessionCallback<WriteResult>, CqlProvider {
|
||||
|
||||
@lombok.NonNull Statement statement;
|
||||
@lombok.NonNull Statement<?> statement;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.SessionCallback#doInSession(org.springframework.data.cassandra.Session)
|
||||
*/
|
||||
@Override
|
||||
public WriteResult doInSession(Session session) throws DriverException, DataAccessException {
|
||||
public WriteResult doInSession(CqlSession session) throws DriverException, DataAccessException {
|
||||
return WriteResult.of(session.execute(this.statement));
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.cql.util.StatementBuilder;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
@@ -31,10 +31,10 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.querybuilder.condition.Condition;
|
||||
import com.datastax.oss.driver.api.querybuilder.delete.Delete;
|
||||
import com.datastax.oss.driver.api.querybuilder.update.Update;
|
||||
|
||||
/**
|
||||
* Common data access operations performed on an entity using a {@link MappingContext} containing mapping metadata.
|
||||
@@ -86,8 +86,8 @@ class EntityOperations {
|
||||
* @return the {@link MappingContext} used by this entity data access operations class.
|
||||
* @see org.springframework.data.cassandra.core.mapping.CassandraMappingContext
|
||||
*/
|
||||
CassandraPersistentEntity<?> getRequiredPersistentEntity(Class<?> entityType) {
|
||||
return getMappingContext().getRequiredPersistentEntity(ClassUtils.getUserClass(entityType));
|
||||
CassandraPersistentEntity<?> getRequiredPersistentEntity(Class<?> entityClass) {
|
||||
return getMappingContext().getRequiredPersistentEntity(ClassUtils.getUserClass(entityClass));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,7 +151,7 @@ class EntityOperations {
|
||||
* @param currentVersionNumber previous version number.
|
||||
* @return the altered {@link Update} containing the {@code IF} condition for optimistic locking.
|
||||
*/
|
||||
Statement appendVersionCondition(Update update, Number currentVersionNumber);
|
||||
void appendVersionCondition(StatementBuilder<Update> update, Number currentVersionNumber);
|
||||
|
||||
/**
|
||||
* Appends a {@code IF} condition to an {@link Delete} statement for optimistic locking to perform the delete only
|
||||
@@ -162,7 +162,7 @@ class EntityOperations {
|
||||
* @return the altered {@link Delete} containing the {@code IF} condition for optimistic locking.
|
||||
* @see #getVersion()
|
||||
*/
|
||||
Statement appendVersionCondition(Delete delete);
|
||||
void appendVersionCondition(StatementBuilder<Delete> delete);
|
||||
|
||||
/**
|
||||
* Initializes the version property of the of the current entity if available.
|
||||
@@ -186,6 +186,14 @@ class EntityOperations {
|
||||
*/
|
||||
@Nullable
|
||||
Number getVersion();
|
||||
|
||||
/**
|
||||
* Returns the {@link CassandraPersistentEntity}.
|
||||
*
|
||||
* @return the {@link CassandraPersistentEntity}.
|
||||
*/
|
||||
CassandraPersistentEntity<?> getPersistentEntity();
|
||||
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@@ -262,21 +270,25 @@ class EntityOperations {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.EntityOperations.AdaptibleEntity#appendVersionCondition(com.datastax.driver.core.querybuilder.Update, java.lang.Number)
|
||||
* @see org.springframework.data.cassandra.core.EntityOperations.AdaptibleEntity#appendVersionCondition(com.datastax.oss.driver.api.querybuilder.update.Update, java.lang.Number)
|
||||
*/
|
||||
@Override
|
||||
public Statement appendVersionCondition(com.datastax.driver.core.querybuilder.Update update,
|
||||
Number currentVersionNumber) {
|
||||
public void appendVersionCondition(StatementBuilder<Update> update, Number currentVersionNumber) {
|
||||
|
||||
return update.onlyIf(QueryBuilder.eq(getVersionColumnName().toCql(), currentVersionNumber));
|
||||
update.bind((statement, factory) -> {
|
||||
return statement.if_(Condition.column(getVersionColumnName()).isEqualTo(factory.create(currentVersionNumber)));
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.EntityOperations.AdaptibleEntity#appendVersionCondition(com.datastax.driver.core.querybuilder.Delete)
|
||||
* @see org.springframework.data.cassandra.core.EntityOperations.AdaptibleEntity#appendVersionCondition(com.datastax.oss.driver.api.querybuilder.delete.Delete)
|
||||
*/
|
||||
@Override
|
||||
public Statement appendVersionCondition(Delete delete) {
|
||||
return delete.onlyIf(QueryBuilder.eq(getVersionColumnName().toCql(), getVersion()));
|
||||
public void appendVersionCondition(StatementBuilder<Delete> delete) {
|
||||
|
||||
delete.bind((statement, factory) -> {
|
||||
return statement.if_(Condition.column(getVersionColumnName()).isEqualTo(factory.create(getVersion())));
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -323,6 +335,14 @@ class EntityOperations {
|
||||
return this.propertyAccessor.getProperty(versionProperty, Number.class);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.EntityOperations.AdaptibleEntity#getPersistentEntity()
|
||||
*/
|
||||
@Override
|
||||
public CassandraPersistentEntity<?> getPersistentEntity() {
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
private CqlIdentifier getVersionColumnName() {
|
||||
return this.entity.getRequiredVersionProperty().getColumnName();
|
||||
}
|
||||
|
||||
@@ -15,43 +15,27 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.cql.QueryOptions;
|
||||
import org.springframework.data.cassandra.core.cql.QueryOptionsUtil;
|
||||
import org.springframework.data.cassandra.core.cql.RowMapper;
|
||||
import org.springframework.data.cassandra.core.cql.WriteOptions;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.core.query.CassandraPageRequest;
|
||||
import org.springframework.data.convert.EntityWriter;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.PagingState;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.Delete.Where;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.ResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
|
||||
/**
|
||||
* Simple utility class for working with the QueryBuilder API using mapped entities.
|
||||
@@ -66,107 +50,6 @@ class EntityQueryUtils {
|
||||
private static final Pattern FROM_REGEX = Pattern.compile(" FROM ([\"]?[\\w]*[\\\\.]?[\\w]*[\"]?)[\\s]?",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
/**
|
||||
* Creates a Query Object for an insert.
|
||||
*
|
||||
* @param tableName the table name, must not be empty and not {@literal null}.
|
||||
* @param objectToInsert the object to save, must not be {@literal null}.
|
||||
* @param options optional {@link WriteOptions} to apply to the {@link Insert} statement, may be {@literal null}.
|
||||
* @param entityWriter the {@link EntityWriter} to write insert values.
|
||||
* @param entity must not be {@literal null}.
|
||||
* @return The Query object to run with session.execute();
|
||||
*/
|
||||
static Insert createInsertQuery(String tableName, Object objectToInsert, WriteOptions options,
|
||||
CassandraConverter entityWriter, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
Assert.hasText(tableName, "TableName must not be empty");
|
||||
Assert.notNull(objectToInsert, "Object to insert must not be null");
|
||||
Assert.notNull(entityWriter, "CassandraConverter must not be null");
|
||||
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
||||
|
||||
Insert insert = addWriteOptions(QueryBuilder.insertInto(tableName), options);
|
||||
|
||||
boolean insertNulls = false;
|
||||
if (options instanceof InsertOptions) {
|
||||
|
||||
InsertOptions insertOptions = (InsertOptions) options;
|
||||
|
||||
insertNulls = insertOptions.isInsertNulls();
|
||||
}
|
||||
|
||||
if (insertNulls) {
|
||||
|
||||
Map<String, Object> toInsert = new LinkedHashMap<>();
|
||||
|
||||
entityWriter.write(objectToInsert, toInsert, entity);
|
||||
|
||||
for (Entry<String, Object> entry : toInsert.entrySet()) {
|
||||
insert.value(entry.getKey(), entry.getValue());
|
||||
}
|
||||
} else {
|
||||
entityWriter.write(objectToInsert, insert);
|
||||
}
|
||||
|
||||
return insert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query Object for an Update. The {@link Update} uses the identity and values from the given
|
||||
* {@code objectsToUpdate}.
|
||||
*
|
||||
* @param tableName the table name, must not be empty and not {@literal null}.
|
||||
* @param objectToUpdate the object to update, must not be {@literal null}.
|
||||
* @param options optional {@link WriteOptions} to apply to the {@link Update} statement.
|
||||
* @param entityWriter the {@link EntityWriter} to write update assignments and where clauses.
|
||||
* @return The Query object to run with session.execute();
|
||||
*/
|
||||
static Update createUpdateQuery(String tableName, Object objectToUpdate, WriteOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) {
|
||||
|
||||
Assert.hasText(tableName, "TableName must not be empty");
|
||||
Assert.notNull(objectToUpdate, "Object to update must not be null");
|
||||
Assert.notNull(entityWriter, "EntityWriter must not be null");
|
||||
|
||||
Update update = addWriteOptions(QueryBuilder.update(tableName), options);
|
||||
|
||||
entityWriter.write(objectToUpdate, update);
|
||||
|
||||
return update;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Delete Query Object from an annotated POJO. The {@link Delete} uses the identity from the given
|
||||
* {@code objectToDelete}.
|
||||
*
|
||||
* @param tableName the table name, must not be empty and not {@literal null}.
|
||||
* @param objectToDelete the object to delete, must not be {@literal null}.
|
||||
* @param options optional {@link QueryOptions} to apply to the {@link Delete} statement.
|
||||
* @param entityWriter the {@link EntityWriter} to write delete where clauses.
|
||||
* @return The Query object to run with session.execute();
|
||||
*/
|
||||
static Delete createDeleteQuery(String tableName, Object objectToDelete, QueryOptions options,
|
||||
EntityWriter<Object, Object> entityWriter) {
|
||||
|
||||
Assert.hasText(tableName, "TableName must not be empty");
|
||||
Assert.notNull(objectToDelete, "Object to delete must not be null");
|
||||
Assert.notNull(entityWriter, "EntityWriter must not be null");
|
||||
|
||||
Delete.Selection deleteSelection = QueryBuilder.delete();
|
||||
Delete delete = deleteSelection.from(tableName);
|
||||
|
||||
if (options instanceof WriteOptions) {
|
||||
addWriteOptions(delete, (WriteOptions) options);
|
||||
} else {
|
||||
QueryOptionsUtil.addQueryOptions(delete, options);
|
||||
}
|
||||
|
||||
Where where = delete.where();
|
||||
|
||||
entityWriter.write(objectToDelete, where);
|
||||
|
||||
return delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a {@link Slice} of data from the {@link ResultSet} for a {@link Pageable}.
|
||||
*
|
||||
@@ -180,8 +63,24 @@ class EntityQueryUtils {
|
||||
|
||||
int toRead = resultSet.getAvailableWithoutFetching();
|
||||
|
||||
return readSlice(() -> Iterators.limit(resultSet.iterator(), toRead), resultSet.getExecutionInfo().getPagingState(),
|
||||
mapper, page, pageSize);
|
||||
return readSlice(() -> limit(resultSet.iterator(), toRead), resultSet.getExecutionInfo().getPagingState(), mapper,
|
||||
page, pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a {@link Slice} of data from the {@link ResultSet} for a {@link Pageable}.
|
||||
*
|
||||
* @param resultSet must not be {@literal null}.
|
||||
* @param mapper must not be {@literal null}.
|
||||
* @param page
|
||||
* @param pageSize
|
||||
* @return the resulting {@link Slice}.
|
||||
* @since 3.0
|
||||
*/
|
||||
static <T> Slice<T> readSlice(AsyncResultSet resultSet, RowMapper<T> mapper, int page, int pageSize) {
|
||||
|
||||
return readSlice(() -> limit(resultSet.currentPage().iterator(), resultSet.remaining()),
|
||||
resultSet.getExecutionInfo().getPagingState(), mapper, page, pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,7 +94,7 @@ class EntityQueryUtils {
|
||||
* @return the resulting {@link Slice}.
|
||||
* @since 2.1
|
||||
*/
|
||||
static <T> Slice<T> readSlice(Iterable<Row> rows, @Nullable PagingState pagingState, RowMapper<T> mapper, int page,
|
||||
static <T> Slice<T> readSlice(Iterable<Row> rows, @Nullable ByteBuffer pagingState, RowMapper<T> mapper, int page,
|
||||
int pageSize) {
|
||||
|
||||
List<T> result = new ArrayList<>(pageSize);
|
||||
@@ -220,19 +119,7 @@ class EntityQueryUtils {
|
||||
* @return
|
||||
* @since 2.1
|
||||
*/
|
||||
static CqlIdentifier getTableName(Statement statement) {
|
||||
|
||||
if (statement instanceof Select) {
|
||||
|
||||
Select select = (Select) statement;
|
||||
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(select);
|
||||
String table = (String) accessor.getPropertyValue("table");
|
||||
|
||||
if (table != null) {
|
||||
return CqlIdentifier.isQuotedIdentifier(table) ? CqlIdentifier.quoted(unquote(table)) : CqlIdentifier.of(table);
|
||||
}
|
||||
}
|
||||
static CqlIdentifier getTableName(Statement<?> statement) {
|
||||
|
||||
String cql = statement.toString();
|
||||
Matcher matcher = FROM_REGEX.matcher(cql);
|
||||
@@ -240,103 +127,52 @@ class EntityQueryUtils {
|
||||
if (matcher.find()) {
|
||||
|
||||
String cqlTableName = matcher.group(1);
|
||||
if (CqlIdentifier.isQuotedIdentifier(cqlTableName)) {
|
||||
return CqlIdentifier.quoted(unquote(cqlTableName));
|
||||
}
|
||||
|
||||
int separator = cqlTableName.indexOf('.');
|
||||
|
||||
if (separator != -1) {
|
||||
return CqlIdentifier.of(cqlTableName.substring(separator + 1));
|
||||
return CqlIdentifier.fromCql(cqlTableName.substring(separator + 1));
|
||||
}
|
||||
|
||||
return CqlIdentifier.of(cqlTableName);
|
||||
return CqlIdentifier.fromCql(cqlTableName);
|
||||
}
|
||||
|
||||
return CqlIdentifier.of("unknown");
|
||||
return CqlIdentifier.fromCql("unknown");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add common {@link WriteOptions} options to {@link Insert} CQL statements.
|
||||
* Returns a view containing the first {@code limitSize} elements of {@code iterator}. If {@code
|
||||
* iterator} contains fewer than {@code limitSize} elements, the returned view contains all of its elements. The
|
||||
* returned iterator supports {@code remove()} if {@code iterator} does.
|
||||
*
|
||||
* @param insert {@link Insert} CQL statement, must not be {@literal null}.
|
||||
* @param writeOptions write options (e.g. consistency level) to add to the CQL statement.
|
||||
* @return the given {@link Insert}.
|
||||
* @see #addWriteOptions(Insert, WriteOptions)
|
||||
* @since 2.1
|
||||
* @param iterator the iterator to limit
|
||||
* @param limitSize the maximum number of elements in the returned iterator
|
||||
* @throws IllegalArgumentException if {@code limitSize} is negative
|
||||
* @since 3.0
|
||||
*/
|
||||
static Insert addWriteOptions(Insert insert, WriteOptions writeOptions) {
|
||||
private static <T> Iterator<T> limit(Iterator<T> iterator, int limitSize) {
|
||||
|
||||
Assert.notNull(insert, "Insert must not be null");
|
||||
return new Iterator<T>() {
|
||||
private int count;
|
||||
|
||||
if (writeOptions instanceof InsertOptions) {
|
||||
|
||||
InsertOptions insertOptions = (InsertOptions) writeOptions;
|
||||
|
||||
if (insertOptions.isIfNotExists()) {
|
||||
insert = insert.ifNotExists();
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return count < limitSize && iterator.hasNext();
|
||||
}
|
||||
}
|
||||
|
||||
QueryOptionsUtil.addWriteOptions(insert, writeOptions);
|
||||
|
||||
return insert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add common {@link WriteOptions} options to {@link Update} CQL statements.
|
||||
*
|
||||
* @param update {@link Update} CQL statement, must not be {@literal null}.
|
||||
* @param writeOptions write options (e.g. consistency level) to add to the CQL statement.
|
||||
* @return the given {@link Update}.
|
||||
* @see QueryOptionsUtil#addWriteOptions(Update, WriteOptions)
|
||||
* @since 2.1
|
||||
*/
|
||||
static Update addWriteOptions(Update update, WriteOptions writeOptions) {
|
||||
|
||||
Assert.notNull(update, "Update must not be null");
|
||||
|
||||
QueryOptionsUtil.addWriteOptions(update, writeOptions);
|
||||
|
||||
if (writeOptions instanceof UpdateOptions) {
|
||||
|
||||
UpdateOptions updateOptions = (UpdateOptions) writeOptions;
|
||||
|
||||
if (updateOptions.isIfExists()) {
|
||||
update.where().ifExists();
|
||||
@Override
|
||||
public T next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
count++;
|
||||
return iterator.next();
|
||||
}
|
||||
}
|
||||
|
||||
return update;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add common {@link WriteOptions} options to {@link Delete} CQL statements.
|
||||
*
|
||||
* @param delete {@link Delete} CQL statement, must not be {@literal null}.
|
||||
* @param writeOptions write options (e.g. consistency level) to add to the CQL statement.
|
||||
* @return the given {@link Delete}.
|
||||
* @since 2.1
|
||||
*/
|
||||
static Delete addWriteOptions(Delete delete, WriteOptions writeOptions) {
|
||||
|
||||
Assert.notNull(delete, "Delete must not be null");
|
||||
|
||||
QueryOptionsUtil.addWriteOptions(delete, writeOptions);
|
||||
|
||||
if (writeOptions instanceof DeleteOptions) {
|
||||
|
||||
DeleteOptions deleteOptions = (DeleteOptions) writeOptions;
|
||||
|
||||
if (deleteOptions.isIfExists()) {
|
||||
delete.where().ifExists();
|
||||
@Override
|
||||
public void remove() {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
return delete;
|
||||
}
|
||||
|
||||
private static String unquote(String identifier) {
|
||||
return identifier.substring(1, identifier.length() - 1);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ package org.springframework.data.cassandra.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.datastax.driver.core.ExecutionInfo;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.ExecutionInfo;
|
||||
import com.datastax.oss.driver.api.core.cql.ResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
|
||||
/**
|
||||
* The result of a write operation for an entity.
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* {@link ExecutableDeleteOperation} allows creation and execution of Cassandra {@code DELETE} operations in a fluent
|
||||
* API style.
|
||||
@@ -72,7 +73,7 @@ public interface ExecutableDeleteOperation {
|
||||
|
||||
Assert.hasText(table, "Table name must not be null or empty");
|
||||
|
||||
return inTable(CqlIdentifier.of(table));
|
||||
return inTable(CqlIdentifier.fromCql(table));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,11 +20,12 @@ import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExecutableDeleteOperation}.
|
||||
*
|
||||
@@ -49,13 +50,6 @@ class ExecutableDeleteOperationSupport implements ExecutableDeleteOperation {
|
||||
return new ExecutableDeleteSupport(this.template, domainType, Query.empty(), null);
|
||||
}
|
||||
|
||||
// TODO: rethink the implementation
|
||||
// While the use of final fields and construction on mutation effectively makes this class Thread-safe,
|
||||
// it is possible this implementation could generate a high-level of young-gen garbage on the JVM heap,
|
||||
// particularly if the template delete(..) (and this class) are used inside of a loop for a large number
|
||||
// of domain types. Of course, this assumption is highly contingent on the user's `Query`
|
||||
// in addition to his/her application design.
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
|
||||
static class ExecutableDeleteSupport implements ExecutableDelete, TerminatingDelete {
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* {@link ExecutableInsertOperation} allows creation and execution of Cassandra {@code INSERT} insert operations in a
|
||||
* fluent API style.
|
||||
@@ -69,7 +70,7 @@ public interface ExecutableInsertOperation {
|
||||
|
||||
Assert.hasText(table, "Table name must not be null or empty");
|
||||
|
||||
return inTable(CqlIdentifier.of(table));
|
||||
return inTable(CqlIdentifier.fromCql(table));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,10 +20,11 @@ import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExecutableInsertOperation}.
|
||||
*
|
||||
@@ -47,12 +48,6 @@ class ExecutableInsertOperationSupport implements ExecutableInsertOperation {
|
||||
return new ExecutableInsertSupport<>(this.template, domainType, InsertOptions.empty(), null);
|
||||
}
|
||||
|
||||
// TODO: rethink the implementation
|
||||
// While the use of final fields and construction on mutation effectively makes this class Thread-safe,
|
||||
// it is possible this implementation could generate a high-level of young-gen garbage on the JVM heap,
|
||||
// particularly if the template insert(..) (and this class) are used inside of a loop for a large number
|
||||
// of domain types. Of course, this assumption is highly contingent on the user's application design.
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
|
||||
static class ExecutableInsertSupport<T> implements ExecutableInsert<T> {
|
||||
|
||||
@@ -19,11 +19,12 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* The {@link ExecutableSelectOperation} interface allows creation and execution of Cassandra {@code SELECT} operations
|
||||
* in a fluent API style.
|
||||
@@ -85,7 +86,7 @@ public interface ExecutableSelectOperation {
|
||||
|
||||
Assert.hasText(table, "Table name must not be null or empty");
|
||||
|
||||
return inTable(CqlIdentifier.of(table));
|
||||
return inTable(CqlIdentifier.fromCql(table));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,12 +24,13 @@ import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExecutableSelectOperation}.
|
||||
*
|
||||
@@ -54,13 +55,6 @@ class ExecutableSelectOperationSupport implements ExecutableSelectOperation {
|
||||
return new ExecutableSelectSupport<>(this.template, domainType, domainType, Query.empty(), null);
|
||||
}
|
||||
|
||||
// TODO: rethink the implementation
|
||||
// While the use of final fields and construction on mutation effectively makes this class Thread-safe,
|
||||
// it is possible this implementation could generate a high-level of young-gen garbage on the JVM heap,
|
||||
// particularly if the template query(..) (and this class) are used inside of a loop for a large number
|
||||
// of domain types. Of course, this assumption is highly contingent on the user's `Query`
|
||||
// in addition to his/her application design.
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
|
||||
static class ExecutableSelectSupport<T> implements ExecutableSelect<T> {
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.data.cassandra.core.query.Update;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* {@link ExecutableUpdateOperation} allows creation and execution of Cassandra {@code UPDATE} operation in a fluent API
|
||||
* style.
|
||||
@@ -78,7 +79,7 @@ public interface ExecutableUpdateOperation {
|
||||
|
||||
Assert.hasText(table, "Table name must not be null or empty");
|
||||
|
||||
return inTable(CqlIdentifier.of(table));
|
||||
return inTable(CqlIdentifier.fromCql(table));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,12 +20,13 @@ import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.data.cassandra.core.query.Update;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ExecutableUpdateOperation}.
|
||||
*
|
||||
@@ -51,13 +52,6 @@ class ExecutableUpdateOperationSupport implements ExecutableUpdateOperation {
|
||||
return new ExecutableUpdateSupport(this.template, domainType, Query.empty(), null);
|
||||
}
|
||||
|
||||
// TODO: rethink the implementation
|
||||
// While the use of final fields and construction on mutation effectively makes this class Thread-safe,
|
||||
// it is possible this implementation could generate a high-level of young-gen garbage on the JVM heap,
|
||||
// particularly if the template update(..) (and this class) are used inside of a loop for a large number
|
||||
// of domain types. Of course, this assumption is highly contingent on the user's `Query`
|
||||
// in addition to his/her application design.
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
|
||||
static class ExecutableUpdateSupport implements ExecutableUpdate, TerminatingUpdate {
|
||||
|
||||
@@ -35,13 +35,11 @@ import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.querybuilder.Batch;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
import com.datastax.oss.driver.api.core.cql.BatchStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.BatchStatementBuilder;
|
||||
import com.datastax.oss.driver.api.core.cql.BatchType;
|
||||
import com.datastax.oss.driver.api.core.cql.BatchableStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||
|
||||
/**
|
||||
* Default implementation for {@link ReactiveCassandraBatchOperations}.
|
||||
@@ -54,13 +52,13 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations
|
||||
|
||||
private final AtomicBoolean executed = new AtomicBoolean();
|
||||
|
||||
private final Batch batch = QueryBuilder.batch();
|
||||
private final BatchStatementBuilder batch = BatchStatement.builder(BatchType.LOGGED);
|
||||
|
||||
private final CassandraConverter converter;
|
||||
|
||||
private final CassandraMappingContext mappingContext;
|
||||
|
||||
private final List<Mono<Collection<? extends BuiltStatement>>> batchMonos = new CopyOnWriteArrayList<>();
|
||||
private final List<Mono<Collection<? extends BatchableStatement<?>>>> batchMonos = new CopyOnWriteArrayList<>();
|
||||
|
||||
private final ReactiveCassandraOperations operations;
|
||||
|
||||
@@ -78,7 +76,7 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations
|
||||
this.operations = operations;
|
||||
this.converter = operations.getConverter();
|
||||
this.mappingContext = this.converter.getMappingContext();
|
||||
this.statementFactory = new StatementFactory(new UpdateMapper(this.converter));
|
||||
this.statementFactory = new StatementFactory(new UpdateMapper(converter));
|
||||
}
|
||||
|
||||
private void assertNotExecuted() {
|
||||
@@ -137,9 +135,9 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations
|
||||
.collectList() //
|
||||
.flatMap(statements -> {
|
||||
|
||||
statements.forEach(this.batch::add);
|
||||
this.batch.addStatements(statements);
|
||||
|
||||
return this.operations.getReactiveCqlOperations().queryForResultSet(this.batch);
|
||||
return this.operations.getReactiveCqlOperations().queryForResultSet(this.batch.build());
|
||||
|
||||
}).flatMap(resultSet -> resultSet.rows().collectList()
|
||||
.map(rows -> new WriteResult(resultSet.getAllExecutionInfo(), resultSet.wasApplied(), rows)));
|
||||
@@ -157,7 +155,7 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations
|
||||
|
||||
assertNotExecuted();
|
||||
|
||||
this.batch.using(QueryBuilder.timestamp(timestamp));
|
||||
this.batch.setQueryTimestamp(timestamp);
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -221,11 +219,10 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations
|
||||
return this;
|
||||
}
|
||||
|
||||
private Collection<? extends BuiltStatement> doInsert(Iterable<?> entities, WriteOptions options) {
|
||||
private Collection<SimpleStatement> doInsert(Iterable<?> entities, WriteOptions options) {
|
||||
|
||||
CassandraConverter converter = getConverter();
|
||||
CassandraMappingContext mappingContext = getMappingContext();
|
||||
List<Insert> insertQueries = new ArrayList<>();
|
||||
List<SimpleStatement> insertQueries = new ArrayList<>();
|
||||
|
||||
for (Object entity : entities) {
|
||||
|
||||
@@ -234,8 +231,8 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations
|
||||
BasicCassandraPersistentEntity<?> persistentEntity = mappingContext
|
||||
.getRequiredPersistentEntity(entity.getClass());
|
||||
|
||||
Insert insertQuery = EntityQueryUtils.createInsertQuery(persistentEntity.getTableName().toCql(), entity, options,
|
||||
converter, persistentEntity);
|
||||
SimpleStatement insertQuery = getStatementFactory()
|
||||
.insert(entity, options, persistentEntity, persistentEntity.getTableName()).build();
|
||||
|
||||
insertQueries.add(insertQuery);
|
||||
}
|
||||
@@ -302,10 +299,9 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations
|
||||
return this;
|
||||
}
|
||||
|
||||
private Collection<? extends BuiltStatement> doUpdate(Iterable<?> entities, WriteOptions options) {
|
||||
private Collection<SimpleStatement> doUpdate(Iterable<?> entities, WriteOptions options) {
|
||||
|
||||
CassandraConverter converter = getConverter();
|
||||
List<Update> updateQueries = new ArrayList<>();
|
||||
List<SimpleStatement> updateQueries = new ArrayList<>();
|
||||
|
||||
for (Object entity : entities) {
|
||||
|
||||
@@ -313,8 +309,8 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations
|
||||
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||
|
||||
Update update = getStatementFactory().update(entity, options, converter, persistentEntity,
|
||||
persistentEntity.getTableName());
|
||||
SimpleStatement update = getStatementFactory()
|
||||
.update(entity, options, persistentEntity, persistentEntity.getTableName()).build();
|
||||
|
||||
updateQueries.add(update);
|
||||
}
|
||||
@@ -381,10 +377,9 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations
|
||||
return this;
|
||||
}
|
||||
|
||||
private Collection<? extends BuiltStatement> doDelete(Iterable<?> entities, WriteOptions options) {
|
||||
private Collection<SimpleStatement> doDelete(Iterable<?> entities, WriteOptions options) {
|
||||
|
||||
CassandraConverter converter = getConverter();
|
||||
List<Delete> deleteQueries = new ArrayList<>();
|
||||
List<SimpleStatement> deleteQueries = new ArrayList<>();
|
||||
|
||||
for (Object entity : entities) {
|
||||
|
||||
@@ -392,8 +387,8 @@ class ReactiveCassandraBatchTemplate implements ReactiveCassandraBatchOperations
|
||||
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||
|
||||
Delete delete = getStatementFactory().delete(entity, options, converter, persistentEntity,
|
||||
persistentEntity.getTableName());
|
||||
SimpleStatement delete = getStatementFactory()
|
||||
.delete(entity, options, getConverter(), persistentEntity.getTableName()).build();
|
||||
|
||||
deleteQueries.add(delete);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.data.cassandra.core.query.Update;
|
||||
import org.springframework.data.domain.Slice;
|
||||
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
|
||||
/**
|
||||
* Interface specifying a basic set of reactive Cassandra operations. Implemented by {@link ReactiveCassandraTemplate}.
|
||||
@@ -98,7 +98,7 @@ public interface ReactiveCassandraOperations extends ReactiveFluentCassandraOper
|
||||
<T> Mono<T> selectOne(String cql, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.Statement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.Statement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -109,7 +109,7 @@ public interface ReactiveCassandraOperations extends ReactiveFluentCassandraOper
|
||||
* @return the result objects returned by the action.
|
||||
* @throws DataAccessException if there is any problem issuing the execution.
|
||||
*/
|
||||
<T> Flux<T> select(Statement statement, Class<T> entityClass) throws DataAccessException;
|
||||
<T> Flux<T> select(Statement<?> statement, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a {@code SELECT} query with paging and convert the result set to a {@link Slice} of entities. A sliced
|
||||
@@ -121,7 +121,7 @@ public interface ReactiveCassandraOperations extends ReactiveFluentCassandraOper
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @since 2.1
|
||||
*/
|
||||
<T> Mono<Slice<T>> slice(Statement statement, Class<T> entityClass) throws DataAccessException;
|
||||
<T> Mono<Slice<T>> slice(Statement<?> statement, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a {@code SELECT} query and convert the resulting item to an entity.
|
||||
@@ -131,7 +131,7 @@ public interface ReactiveCassandraOperations extends ReactiveFluentCassandraOper
|
||||
* @return the result object returned by the action or {@link Mono#empty()}
|
||||
* @throws DataAccessException if there is any problem issuing the execution.
|
||||
*/
|
||||
<T> Mono<T> selectOne(Statement statement, Class<T> entityClass) throws DataAccessException;
|
||||
<T> Mono<T> selectOne(Statement<?> statement, Class<T> entityClass) throws DataAccessException;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with org.springframework.data.cassandra.core.query.Query
|
||||
|
||||
@@ -39,10 +39,7 @@ import org.springframework.data.cassandra.ReactiveSessionFactory;
|
||||
import org.springframework.data.cassandra.core.EntityOperations.AdaptibleEntity;
|
||||
import org.springframework.data.cassandra.core.convert.CassandraConverter;
|
||||
import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
|
||||
import org.springframework.data.cassandra.core.convert.QueryMapper;
|
||||
import org.springframework.data.cassandra.core.convert.UpdateMapper;
|
||||
import org.springframework.data.cassandra.core.cql.CassandraAccessor;
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.cql.CqlProvider;
|
||||
import org.springframework.data.cassandra.core.cql.QueryOptions;
|
||||
import org.springframework.data.cassandra.core.cql.ReactiveCqlOperations;
|
||||
@@ -51,6 +48,7 @@ import org.springframework.data.cassandra.core.cql.ReactiveSessionCallback;
|
||||
import org.springframework.data.cassandra.core.cql.RowMapper;
|
||||
import org.springframework.data.cassandra.core.cql.WriteOptions;
|
||||
import org.springframework.data.cassandra.core.cql.session.DefaultReactiveSessionFactory;
|
||||
import org.springframework.data.cassandra.core.cql.util.StatementBuilder;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.core.mapping.event.AfterConvertEvent;
|
||||
import org.springframework.data.cassandra.core.mapping.event.AfterDeleteEvent;
|
||||
@@ -72,18 +70,19 @@ import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.RegularStatement;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.SimpleStatement;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
import com.datastax.driver.core.querybuilder.Truncate;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
|
||||
import com.datastax.oss.driver.api.core.context.DriverContext;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
import com.datastax.oss.driver.api.querybuilder.QueryBuilder;
|
||||
import com.datastax.oss.driver.api.querybuilder.delete.Delete;
|
||||
import com.datastax.oss.driver.api.querybuilder.insert.RegularInsert;
|
||||
import com.datastax.oss.driver.api.querybuilder.select.Select;
|
||||
import com.datastax.oss.driver.api.querybuilder.truncate.Truncate;
|
||||
import com.datastax.oss.driver.api.querybuilder.update.Update;
|
||||
|
||||
/**
|
||||
* Primary implementation of {@link ReactiveCassandraOperations}. It simplifies the use of Reactive Cassandra usage and
|
||||
@@ -180,7 +179,7 @@ public class ReactiveCassandraTemplate
|
||||
this.cqlOperations = reactiveCqlOperations;
|
||||
this.entityOperations = new EntityOperations(converter.getMappingContext());
|
||||
this.projectionFactory = new SpelAwareProxyProjectionFactory();
|
||||
this.statementFactory = new StatementFactory(new QueryMapper(converter), new UpdateMapper(converter));
|
||||
this.statementFactory = new StatementFactory(converter);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -278,7 +277,7 @@ public class ReactiveCassandraTemplate
|
||||
}
|
||||
|
||||
CqlIdentifier getTableName(Class<?> entityClass) {
|
||||
return getEntityOperations().getTableName(entityClass);
|
||||
return getRequiredPersistentEntity(entityClass).getTableName();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -293,7 +292,7 @@ public class ReactiveCassandraTemplate
|
||||
|
||||
Assert.hasText(cql, "CQL must not be empty");
|
||||
|
||||
return select(new SimpleStatement(cql), entityClass);
|
||||
return select(SimpleStatement.newInstance(cql), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -305,36 +304,36 @@ public class ReactiveCassandraTemplate
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.Statement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.Statement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#select(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#select(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> Flux<T> select(Statement statement, Class<T> entityClass) {
|
||||
public <T> Flux<T> select(Statement<?> statement, Class<T> entityClass) {
|
||||
|
||||
Assert.notNull(statement, "Statement must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
Function<Row, T> mapper = getMapper(entityClass, entityClass, EntityQueryUtils.getTableName(statement));
|
||||
Function<Row, T> mapper = getMapper(entityClass, entityClass, null);
|
||||
|
||||
return getReactiveCqlOperations().query(statement, (row, rowNum) -> mapper.apply(row));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#selectOne(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations#selectOne(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> Mono<T> selectOne(Statement statement, Class<T> entityClass) {
|
||||
public <T> Mono<T> selectOne(Statement<?> statement, Class<T> entityClass) {
|
||||
return select(statement, entityClass).next();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#slice(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.CassandraOperations#slice(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> Mono<Slice<T>> slice(Statement statement, Class<T> entityClass) {
|
||||
public <T> Mono<Slice<T>> slice(Statement<?> statement, Class<T> entityClass) {
|
||||
|
||||
Assert.notNull(statement, "Statement must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
@@ -379,11 +378,11 @@ public class ReactiveCassandraTemplate
|
||||
|
||||
Query queryToUse = query.columns(columns);
|
||||
|
||||
RegularStatement select = getStatementFactory().select(queryToUse, persistentEntity, tableName);
|
||||
StatementBuilder<Select> select = getStatementFactory().select(queryToUse, persistentEntity, tableName);
|
||||
|
||||
Function<Row, T> mapper = getMapper(entityClass, returnType, tableName);
|
||||
|
||||
return getReactiveCqlOperations().query(select, (row, rowNum) -> mapper.apply(row));
|
||||
return getReactiveCqlOperations().query(select.build(), (row, rowNum) -> mapper.apply(row));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -407,9 +406,9 @@ public class ReactiveCassandraTemplate
|
||||
Assert.notNull(query, "Query must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
RegularStatement select = getStatementFactory().select(query, getRequiredPersistentEntity(entityClass));
|
||||
StatementBuilder<Select> select = getStatementFactory().select(query, getRequiredPersistentEntity(entityClass));
|
||||
|
||||
return slice(select, entityClass);
|
||||
return slice(select.build(), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -429,10 +428,10 @@ public class ReactiveCassandraTemplate
|
||||
Mono<WriteResult> doUpdate(Query query, org.springframework.data.cassandra.core.query.Update update,
|
||||
Class<?> entityClass, CqlIdentifier tableName) {
|
||||
|
||||
RegularStatement statement = getStatementFactory().update(query, update, getRequiredPersistentEntity(entityClass),
|
||||
tableName);
|
||||
StatementBuilder<Update> statement = getStatementFactory().update(query, update,
|
||||
getRequiredPersistentEntity(entityClass), tableName);
|
||||
|
||||
return getReactiveCqlOperations().execute(new StatementCallback(statement)).next();
|
||||
return getReactiveCqlOperations().execute(new StatementCallback(statement.build())).next();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -449,7 +448,10 @@ public class ReactiveCassandraTemplate
|
||||
|
||||
Mono<WriteResult> doDelete(Query query, Class<?> entityClass, CqlIdentifier tableName) {
|
||||
|
||||
RegularStatement delete = getStatementFactory().delete(query, getRequiredPersistentEntity(entityClass), tableName);
|
||||
StatementBuilder<Delete> builder = getStatementFactory().delete(query, getRequiredPersistentEntity(entityClass),
|
||||
tableName);
|
||||
|
||||
SimpleStatement delete = builder.build();
|
||||
|
||||
Mono<WriteResult> writeResult = getReactiveCqlOperations().execute(new StatementCallback(delete))
|
||||
.doOnSubscribe(it -> maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName))).next();
|
||||
@@ -469,9 +471,7 @@ public class ReactiveCassandraTemplate
|
||||
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
Select select = QueryBuilder.select().countAll().from(getTableName(entityClass).toCql());
|
||||
|
||||
return getReactiveCqlOperations().queryForObject(select, Long.class);
|
||||
return doCount(Query.empty(), entityClass, getTableName(entityClass));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -488,9 +488,10 @@ public class ReactiveCassandraTemplate
|
||||
|
||||
Mono<Long> doCount(Query query, Class<?> entityClass, CqlIdentifier tableName) {
|
||||
|
||||
RegularStatement count = getStatementFactory().count(query, getRequiredPersistentEntity(entityClass), tableName);
|
||||
StatementBuilder<Select> count = getStatementFactory().count(query, getRequiredPersistentEntity(entityClass),
|
||||
tableName);
|
||||
|
||||
return getReactiveCqlOperations().queryForObject(count, Long.class).switchIfEmpty(Mono.just(0L));
|
||||
return getReactiveCqlOperations().queryForObject(count.build(), Long.class).switchIfEmpty(Mono.just(0L));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -502,13 +503,10 @@ public class ReactiveCassandraTemplate
|
||||
Assert.notNull(id, "Id must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);
|
||||
StatementBuilder<Select> builder = getStatementFactory().selectOneById(id, getConverter(),
|
||||
getTableName(entityClass));
|
||||
|
||||
Select select = QueryBuilder.select().from(entity.getTableName().toCql());
|
||||
|
||||
getConverter().write(id, select.where(), entity);
|
||||
|
||||
return getReactiveCqlOperations().queryForRows(select).hasElements();
|
||||
return getReactiveCqlOperations().queryForRows(builder.build()).hasElements();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -525,10 +523,10 @@ public class ReactiveCassandraTemplate
|
||||
|
||||
Mono<Boolean> doExists(Query query, Class<?> entityClass, CqlIdentifier tableName) {
|
||||
|
||||
RegularStatement select = getStatementFactory().select(query.limit(1), getRequiredPersistentEntity(entityClass),
|
||||
tableName);
|
||||
StatementBuilder<Select> builder = getStatementFactory().select(query.limit(1),
|
||||
getRequiredPersistentEntity(entityClass), tableName);
|
||||
|
||||
return getReactiveCqlOperations().queryForRows(select).hasElements();
|
||||
return getReactiveCqlOperations().queryForRows(builder.build()).hasElements();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -540,13 +538,10 @@ public class ReactiveCassandraTemplate
|
||||
Assert.notNull(id, "Id must not be null");
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);
|
||||
StatementBuilder<Select> builder = getStatementFactory().selectOneById(id, getConverter(),
|
||||
getTableName(entityClass));
|
||||
|
||||
Select select = QueryBuilder.select().all().from(entity.getTableName().toCql());
|
||||
|
||||
getConverter().write(id, select.where(), entity);
|
||||
|
||||
return selectOne(select, entityClass);
|
||||
return selectOne(builder.build(), entityClass);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -579,15 +574,16 @@ public class ReactiveCassandraTemplate
|
||||
|
||||
T entityToUse = source.isVersionedEntity() ? source.initializeVersionProperty() : entityToInsert;
|
||||
|
||||
Insert insert = EntityQueryUtils.createInsertQuery(tableName.toCql(), entityToUse, options, getConverter(),
|
||||
persistentEntity);
|
||||
StatementBuilder<RegularInsert> builder = getStatementFactory().insert(entityToUse, options, persistentEntity,
|
||||
tableName);
|
||||
SimpleStatement insert = builder.build();
|
||||
|
||||
return source.isVersionedEntity() ? doInsertVersioned(insert.ifNotExists(), entityToUse, source, tableName)
|
||||
return source.isVersionedEntity() ? doInsertVersioned(insert, entityToUse, source, tableName)
|
||||
: doInsert(insert, entityToUse, tableName);
|
||||
});
|
||||
}
|
||||
|
||||
private <T> Mono<EntityWriteResult<T>> doInsertVersioned(Insert insert, T entity, AdaptibleEntity<T> source,
|
||||
private <T> Mono<EntityWriteResult<T>> doInsertVersioned(Statement<?> insert, T entity, AdaptibleEntity<T> source,
|
||||
CqlIdentifier tableName) {
|
||||
|
||||
return executeSave(entity, tableName, insert, (result, sink) -> {
|
||||
@@ -605,7 +601,7 @@ public class ReactiveCassandraTemplate
|
||||
});
|
||||
}
|
||||
|
||||
private <T> Mono<EntityWriteResult<T>> doInsert(Insert insert, T entity, CqlIdentifier tableName) {
|
||||
private <T> Mono<EntityWriteResult<T>> doInsert(Statement<?> insert, T entity, CqlIdentifier tableName) {
|
||||
return executeSave(entity, tableName, insert);
|
||||
}
|
||||
|
||||
@@ -644,9 +640,12 @@ public class ReactiveCassandraTemplate
|
||||
Number previousVersion = source.getVersion();
|
||||
T toSave = source.incrementVersion();
|
||||
|
||||
Update update = getStatementFactory().update(toSave, options, getConverter(), persistentEntity, tableName);
|
||||
StatementBuilder<Update> builder = getStatementFactory().update(toSave, options, persistentEntity, tableName);
|
||||
|
||||
return executeSave(toSave, tableName, source.appendVersionCondition(update, previousVersion), (result, sink) -> {
|
||||
source.appendVersionCondition(builder, previousVersion);
|
||||
SimpleStatement update = builder.build();
|
||||
|
||||
return executeSave(toSave, tableName, update, (result, sink) -> {
|
||||
|
||||
if (!result.wasApplied()) {
|
||||
|
||||
@@ -664,9 +663,9 @@ public class ReactiveCassandraTemplate
|
||||
private <T> Mono<EntityWriteResult<T>> doUpdate(T entity, UpdateOptions options, CqlIdentifier tableName,
|
||||
CassandraPersistentEntity<?> persistentEntity) {
|
||||
|
||||
Update update = getStatementFactory().update(entity, options, getConverter(), persistentEntity, tableName);
|
||||
StatementBuilder<Update> builder = getStatementFactory().update(entity, options, persistentEntity, tableName);
|
||||
|
||||
return executeSave(entity, tableName, update);
|
||||
return executeSave(entity, tableName, builder.build());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -690,16 +689,17 @@ public class ReactiveCassandraTemplate
|
||||
CassandraPersistentEntity<?> persistentEntity = getRequiredPersistentEntity(entity.getClass());
|
||||
CqlIdentifier tableName = persistentEntity.getTableName();
|
||||
|
||||
Delete delete = getStatementFactory().delete(entity, options, getConverter(), persistentEntity, tableName);
|
||||
StatementBuilder<Delete> builder = getStatementFactory().delete(entity, options, getConverter(), tableName);
|
||||
SimpleStatement delete = builder.build();
|
||||
|
||||
return source.isVersionedEntity() ? doDeleteVersioned(delete, entity, source, tableName)
|
||||
: doDelete(delete, entity, tableName);
|
||||
}
|
||||
|
||||
private Mono<WriteResult> doDeleteVersioned(Delete delete, Object entity, AdaptibleEntity<Object> source,
|
||||
private Mono<WriteResult> doDeleteVersioned(Statement<?> delete, Object entity, AdaptibleEntity<Object> source,
|
||||
CqlIdentifier tableName) {
|
||||
|
||||
return executeDelete(entity, tableName, source.appendVersionCondition(delete), (result, sink) -> {
|
||||
return executeDelete(entity, tableName, delete, (result, sink) -> {
|
||||
|
||||
if (!result.wasApplied()) {
|
||||
|
||||
@@ -714,7 +714,7 @@ public class ReactiveCassandraTemplate
|
||||
});
|
||||
}
|
||||
|
||||
private Mono<WriteResult> doDelete(Delete delete, Object entity, CqlIdentifier tableName) {
|
||||
private Mono<WriteResult> doDelete(Statement<?> delete, Object entity, CqlIdentifier tableName) {
|
||||
return executeDelete(entity, tableName, delete, (result, sink) -> sink.next(result));
|
||||
}
|
||||
|
||||
@@ -729,9 +729,9 @@ public class ReactiveCassandraTemplate
|
||||
|
||||
CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);
|
||||
CqlIdentifier tableName = entity.getTableName();
|
||||
Delete delete = QueryBuilder.delete().from(tableName.toCql());
|
||||
|
||||
getConverter().write(id, delete.where(), entity);
|
||||
StatementBuilder<Delete> builder = getStatementFactory().deleteById(id, getConverter(), tableName);
|
||||
SimpleStatement delete = builder.build();
|
||||
|
||||
Mono<Boolean> result = getReactiveCqlOperations().execute(delete)
|
||||
.doOnSubscribe(it -> maybeEmitEvent(new BeforeDeleteEvent<>(delete, entityClass, tableName)));
|
||||
@@ -748,12 +748,13 @@ public class ReactiveCassandraTemplate
|
||||
Assert.notNull(entityClass, "Entity type must not be null");
|
||||
|
||||
CqlIdentifier tableName = getTableName(entityClass);
|
||||
Truncate truncate = QueryBuilder.truncate(tableName.toCql());
|
||||
Truncate truncate = QueryBuilder.truncate(tableName);
|
||||
SimpleStatement statement = truncate.build();
|
||||
|
||||
Mono<Boolean> result = getReactiveCqlOperations().execute(truncate)
|
||||
.doOnSubscribe(it -> maybeEmitEvent(new BeforeDeleteEvent<>(truncate, entityClass, tableName)));
|
||||
Mono<Boolean> result = getReactiveCqlOperations().execute(statement)
|
||||
.doOnSubscribe(it -> maybeEmitEvent(new BeforeDeleteEvent<>(statement, entityClass, tableName)));
|
||||
|
||||
return result.doOnNext(it -> maybeEmitEvent(new AfterDeleteEvent<>(truncate, entityClass, tableName))).then();
|
||||
return result.doOnNext(it -> maybeEmitEvent(new AfterDeleteEvent<>(statement, entityClass, tableName))).then();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -796,11 +797,11 @@ public class ReactiveCassandraTemplate
|
||||
// Implementation hooks and utility methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private <T> Mono<EntityWriteResult<T>> executeSave(T entity, CqlIdentifier tableName, Statement statement) {
|
||||
private <T> Mono<EntityWriteResult<T>> executeSave(T entity, CqlIdentifier tableName, Statement<?> statement) {
|
||||
return executeSave(entity, tableName, statement, (writeResult, sink) -> sink.next(writeResult));
|
||||
}
|
||||
|
||||
private <T> Mono<EntityWriteResult<T>> executeSave(T entity, CqlIdentifier tableName, Statement statement,
|
||||
private <T> Mono<EntityWriteResult<T>> executeSave(T entity, CqlIdentifier tableName, Statement<?> statement,
|
||||
BiConsumer<EntityWriteResult<T>, SynchronousSink<EntityWriteResult<T>>> handler) {
|
||||
|
||||
return Mono.defer(() -> {
|
||||
@@ -817,7 +818,7 @@ public class ReactiveCassandraTemplate
|
||||
|
||||
}
|
||||
|
||||
private Mono<WriteResult> executeDelete(Object entity, CqlIdentifier tableName, Statement statement,
|
||||
private Mono<WriteResult> executeDelete(Object entity, CqlIdentifier tableName, Statement<?> statement,
|
||||
BiConsumer<WriteResult, SynchronousSink<WriteResult>> handler) {
|
||||
|
||||
maybeEmitEvent(new BeforeDeleteEvent<>(statement, entity.getClass(), tableName));
|
||||
@@ -830,10 +831,14 @@ public class ReactiveCassandraTemplate
|
||||
.next();
|
||||
}
|
||||
|
||||
private Mono<Integer> getEffectiveFetchSize(Statement statement) {
|
||||
private int getConfiguredPageSize(DriverContext context) {
|
||||
return context.getConfig().getDefaultProfile().getInt(DefaultDriverOption.REQUEST_PAGE_SIZE, 5000);
|
||||
}
|
||||
|
||||
if (statement.getFetchSize() > 0) {
|
||||
return Mono.just(statement.getFetchSize());
|
||||
private Mono<Integer> getEffectiveFetchSize(Statement<?> statement) {
|
||||
|
||||
if (statement.getPageSize() > 0) {
|
||||
return Mono.just(statement.getPageSize());
|
||||
}
|
||||
|
||||
if (getReactiveCqlOperations() instanceof CassandraAccessor) {
|
||||
@@ -843,8 +848,9 @@ public class ReactiveCassandraTemplate
|
||||
}
|
||||
}
|
||||
|
||||
return getReactiveCqlOperations().execute((ReactiveSessionCallback<Integer>) session -> Mono
|
||||
.just(session.getCluster().getConfiguration().getQueryOptions().getFetchSize())).single();
|
||||
return getReactiveCqlOperations()
|
||||
.execute((ReactiveSessionCallback<Integer>) session -> Mono.just(getConfiguredPageSize(session.getContext())))
|
||||
.single();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -897,7 +903,7 @@ public class ReactiveCassandraTemplate
|
||||
return Mono.just(object);
|
||||
}
|
||||
|
||||
protected <T> Mono<T> maybeCallBeforeSave(T object, CqlIdentifier tableName, Statement statement) {
|
||||
protected <T> Mono<T> maybeCallBeforeSave(T object, CqlIdentifier tableName, Statement<?> statement) {
|
||||
|
||||
if (null != entityCallbacks) {
|
||||
return entityCallbacks.callback(ReactiveBeforeSaveCallback.class, object, tableName, statement);
|
||||
@@ -909,7 +915,7 @@ public class ReactiveCassandraTemplate
|
||||
@Value
|
||||
static class StatementCallback implements ReactiveSessionCallback<WriteResult>, CqlProvider {
|
||||
|
||||
@lombok.NonNull Statement statement;
|
||||
@lombok.NonNull Statement<?> statement;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.ReactiveSessionCallback#doInSession(org.springframework.data.cassandra.ReactiveSession)
|
||||
|
||||
@@ -17,10 +17,11 @@ package org.springframework.data.cassandra.core;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* The {@link ReactiveDeleteOperation} interface allows creation and execution of Cassandra {@code DELETE} operations in
|
||||
* a fluent API style.
|
||||
@@ -76,7 +77,7 @@ public interface ReactiveDeleteOperation {
|
||||
|
||||
Assert.hasText(table, "Table name must not be null or empty");
|
||||
|
||||
return inTable(CqlIdentifier.of(table));
|
||||
return inTable(CqlIdentifier.fromCql(table));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,11 +21,12 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ReactiveDeleteOperation}.
|
||||
*
|
||||
|
||||
@@ -17,9 +17,10 @@ package org.springframework.data.cassandra.core;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* The {@link ReactiveInsertOperation} interface allows creation and execution of Cassandra {@code INSERT} operations in
|
||||
* a fluent API style.
|
||||
@@ -73,7 +74,7 @@ public interface ReactiveInsertOperation {
|
||||
|
||||
Assert.hasText(table, "Table must not be null or empty");
|
||||
|
||||
return inTable(CqlIdentifier.of(table));
|
||||
return inTable(CqlIdentifier.fromCql(table));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,10 +21,11 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ReactiveInsertOperation}.
|
||||
*
|
||||
|
||||
@@ -18,10 +18,11 @@ package org.springframework.data.cassandra.core;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* The {@link ReactiveSelectOperation} interface allows creation and execution of Cassandra {@code SELECT} operations in
|
||||
* a fluent API style.
|
||||
@@ -83,7 +84,7 @@ public interface ReactiveSelectOperation {
|
||||
|
||||
Assert.hasText(table, "Table name must not be null or empty");
|
||||
|
||||
return inTable(CqlIdentifier.of(table));
|
||||
return inTable(CqlIdentifier.fromCql(table));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,11 +23,12 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ReactiveSelectOperation}.
|
||||
*
|
||||
|
||||
@@ -17,11 +17,12 @@ package org.springframework.data.cassandra.core;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.data.cassandra.core.query.Update;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* The {@link ReactiveUpdateOperation} interface allows creation and execution of Cassandra {@code UPDATE} operations in
|
||||
* a fluent API style.
|
||||
@@ -81,7 +82,7 @@ public interface ReactiveUpdateOperation {
|
||||
|
||||
Assert.hasText(table, "Table name must not be null or empty");
|
||||
|
||||
return inTable(CqlIdentifier.of(table));
|
||||
return inTable(CqlIdentifier.fromCql(table));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,12 +21,13 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.query.Query;
|
||||
import org.springframework.data.cassandra.core.query.Update;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ReactiveUpdateOperation}.
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,9 +21,9 @@ import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.ExecutionInfo;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.ExecutionInfo;
|
||||
import com.datastax.oss.driver.api.core.cql.ResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
|
||||
/**
|
||||
* The result of a write operation.
|
||||
@@ -49,7 +49,7 @@ public class WriteResult {
|
||||
|
||||
WriteResult(ResultSet resultSet) {
|
||||
|
||||
this.executionInfo = resultSet.getAllExecutionInfo();
|
||||
this.executionInfo = resultSet.getExecutionInfos();
|
||||
this.wasApplied = resultSet.wasApplied();
|
||||
|
||||
int limit = resultSet.getAvailableWithoutFetching();
|
||||
|
||||
@@ -15,14 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.CodecRegistry;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||
|
||||
/**
|
||||
* {@link CassandraValueProvider} to read property values from a {@link Row}.
|
||||
@@ -31,12 +28,10 @@ import com.datastax.driver.core.Row;
|
||||
* @author Matthew T. Adams
|
||||
* @author David Webb
|
||||
* @author Mark Paluch
|
||||
* @deprecated since 3.0, use directly {@link RowValueProvider}.
|
||||
*/
|
||||
public class BasicCassandraRowValueProvider implements CassandraRowValueProvider {
|
||||
|
||||
private final ColumnReader reader;
|
||||
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
@Deprecated
|
||||
public class BasicCassandraRowValueProvider extends RowValueProvider {
|
||||
|
||||
/**
|
||||
* Create a new {@link BasicCassandraRowValueProvider} with the given {@link Row}, {@link CodecRegistry} and
|
||||
@@ -48,13 +43,7 @@ public class BasicCassandraRowValueProvider implements CassandraRowValueProvider
|
||||
* @since 2.1
|
||||
*/
|
||||
public BasicCassandraRowValueProvider(Row source, CodecRegistry codecRegistry, SpELExpressionEvaluator evaluator) {
|
||||
|
||||
Assert.notNull(source, "Source Row must not be null");
|
||||
Assert.notNull(codecRegistry, "CodecRegistry must not be null");
|
||||
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null");
|
||||
|
||||
this.reader = new ColumnReader(source, codecRegistry);
|
||||
this.evaluator = evaluator;
|
||||
super(source, evaluator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,35 +56,7 @@ public class BasicCassandraRowValueProvider implements CassandraRowValueProvider
|
||||
*/
|
||||
@Deprecated
|
||||
public BasicCassandraRowValueProvider(Row source, DefaultSpELExpressionEvaluator evaluator) {
|
||||
this(source, CodecRegistry.DEFAULT_INSTANCE, evaluator);
|
||||
super(source, evaluator);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getPropertyValue(CassandraPersistentProperty property) {
|
||||
|
||||
String spelExpression = property.getSpelExpression();
|
||||
|
||||
return spelExpression != null ? this.evaluator.evaluate(spelExpression)
|
||||
: (T) this.reader.get(property.getRequiredColumnName());
|
||||
}
|
||||
|
||||
public Row getRow() {
|
||||
return this.reader.getRow();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.convert.CassandraValueProvider#hasProperty(org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasProperty(CassandraPersistentProperty property) {
|
||||
|
||||
Assert.notNull(property, "CassandraPersistentProperty must not be null");
|
||||
|
||||
return this.reader.contains(property.getRequiredColumnName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.datastax.driver.core.DataType.Name;
|
||||
|
||||
/**
|
||||
* Value object to capture custom conversion. {@link CassandraCustomConversions} also act as factory for
|
||||
* {@link SimpleTypeHolder}
|
||||
@@ -75,7 +73,7 @@ public class CassandraCustomConversions extends org.springframework.data.convert
|
||||
|
||||
CassandraType annotation = AnnotatedElementUtils.getMergedAnnotation(it, CassandraType.class);
|
||||
|
||||
return annotation != null && annotation.type() == Name.TIME;
|
||||
return annotation != null && annotation.type() == CassandraSimpleTypeHolder.Name.TIME;
|
||||
}) //
|
||||
.map(it -> {
|
||||
|
||||
|
||||
@@ -20,16 +20,15 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.LocalTime;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.datastax.driver.core.DataType.Name;
|
||||
|
||||
/**
|
||||
* Helper class to register JSR-310 specific {@link Converter} implementations to convert between Cassandra types in
|
||||
* case the library is present on the classpath.
|
||||
@@ -60,47 +59,12 @@ public abstract class CassandraJodaTimeConverters {
|
||||
|
||||
List<Converter<?, ?>> converters = new ArrayList<>();
|
||||
|
||||
converters.add(CassandraLocalDateToLocalDateConverter.INSTANCE);
|
||||
converters.add(LocalDateToCassandraLocalDateConverter.INSTANCE);
|
||||
converters.add(MillisOfDayToLocalTimeConverter.INSTANCE);
|
||||
converters.add(LocalTimeToMillisOfDayConverter.INSTANCE);
|
||||
|
||||
return converters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple singleton to convert {@link com.datastax.driver.core.LocalDate}s to their {@link LocalDate} representation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public enum CassandraLocalDateToLocalDateConverter
|
||||
implements Converter<com.datastax.driver.core.LocalDate, LocalDate> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public LocalDate convert(com.datastax.driver.core.LocalDate source) {
|
||||
return new LocalDate(source.getYear(), source.getMonth(), source.getDay());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple singleton to convert {@link LocalDate}s to their {@link com.datastax.driver.core.LocalDate} representation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public enum LocalDateToCassandraLocalDateConverter
|
||||
implements Converter<LocalDate, com.datastax.driver.core.LocalDate> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public com.datastax.driver.core.LocalDate convert(LocalDate source) {
|
||||
return com.datastax.driver.core.LocalDate.fromYearMonthDay(source.getYear(), source.getMonthOfYear(),
|
||||
source.getDayOfMonth());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple singleton to convert {@link Long}s to their {@link LocalTime} representation.
|
||||
*
|
||||
@@ -123,7 +87,7 @@ public abstract class CassandraJodaTimeConverters {
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@WritingConverter
|
||||
@CassandraType(type = Name.TIME)
|
||||
@CassandraType(type = CassandraSimpleTypeHolder.Name.TIME)
|
||||
public enum LocalTimeToMillisOfDayConverter implements Converter<LocalTime, Long> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -15,21 +15,18 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
|
||||
import com.datastax.driver.core.DataType.Name;
|
||||
|
||||
/**
|
||||
* Helper class to register JodaTime specific {@link Converter} implementations in case the library is present on the
|
||||
* classpath.
|
||||
@@ -51,49 +48,12 @@ public abstract class CassandraJsr310Converters {
|
||||
|
||||
List<Converter<?, ?>> converters = new ArrayList<>();
|
||||
|
||||
converters.add(CassandraLocalDateToLocalDateConverter.INSTANCE);
|
||||
converters.add(LocalDateToCassandraLocalDateConverter.INSTANCE);
|
||||
converters.add(MillisOfDayToLocalTimeConverter.INSTANCE);
|
||||
converters.add(LocalTimeToMillisOfDayConverter.INSTANCE);
|
||||
|
||||
return converters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple singleton to convert {@link com.datastax.driver.core.LocalDate}s to their {@link LocalDate} representation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@ReadingConverter
|
||||
public enum CassandraLocalDateToLocalDateConverter
|
||||
implements Converter<com.datastax.driver.core.LocalDate, LocalDate> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public LocalDate convert(com.datastax.driver.core.LocalDate source) {
|
||||
return LocalDate.of(source.getYear(), source.getMonth(), source.getDay());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple singleton to convert {@link LocalDate}s to their {@link com.datastax.driver.core.LocalDate} representation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@WritingConverter
|
||||
public enum LocalDateToCassandraLocalDateConverter
|
||||
implements Converter<LocalDate, com.datastax.driver.core.LocalDate> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public com.datastax.driver.core.LocalDate convert(LocalDate source) {
|
||||
return com.datastax.driver.core.LocalDate.fromYearMonthDay(source.getYear(), source.getMonthValue(),
|
||||
source.getDayOfMonth());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple singleton to convert {@link Long}s to their {@link LocalTime} representation.
|
||||
*
|
||||
@@ -118,7 +78,7 @@ public abstract class CassandraJsr310Converters {
|
||||
* @since 2.1
|
||||
*/
|
||||
@WritingConverter
|
||||
@CassandraType(type = Name.TIME)
|
||||
@CassandraType(type = CassandraSimpleTypeHolder.Name.TIME)
|
||||
public enum LocalTimeToMillisOfDayConverter implements Converter<LocalTime, Long> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import com.datastax.driver.core.Row;
|
||||
|
||||
/**
|
||||
* {@link CassandraValueProvider} providing values based on a {@link Row}.
|
||||
* {@link CassandraValueProvider} providing values based on a {@link com.datastax.oss.driver.api.core.cql.Row}.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
|
||||
@@ -22,17 +22,16 @@ import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraSimpleTypeHolder;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraType;
|
||||
import org.springframework.data.convert.ReadingConverter;
|
||||
import org.springframework.data.convert.ThreeTenBackPortConverters;
|
||||
import org.springframework.data.convert.WritingConverter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.threeten.bp.LocalDate;
|
||||
|
||||
import org.threeten.bp.LocalTime;
|
||||
import org.threeten.bp.temporal.ChronoField;
|
||||
|
||||
import com.datastax.driver.core.DataType.Name;
|
||||
|
||||
/**
|
||||
* Helper class to register {@link Converter} implementations for the ThreeTen Backport project in case it's present on
|
||||
* the classpath.
|
||||
@@ -65,47 +64,12 @@ public abstract class CassandraThreeTenBackPortConverters {
|
||||
|
||||
List<Converter<?, ?>> converters = new ArrayList<>();
|
||||
|
||||
converters.add(CassandraLocalDateToLocalDateConverter.INSTANCE);
|
||||
converters.add(LocalDateToCassandraLocalDateConverter.INSTANCE);
|
||||
converters.add(MillisOfDayToLocalTimeConverter.INSTANCE);
|
||||
converters.add(LocalTimeToMillisOfDayConverter.INSTANCE);
|
||||
|
||||
return converters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple singleton to convert {@link com.datastax.driver.core.LocalDate}s to their {@link LocalDate} representation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public enum CassandraLocalDateToLocalDateConverter
|
||||
implements Converter<com.datastax.driver.core.LocalDate, LocalDate> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public LocalDate convert(com.datastax.driver.core.LocalDate source) {
|
||||
return LocalDate.of(source.getYear(), source.getMonth(), source.getDay());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple singleton to convert {@link LocalDate}s to their {@link com.datastax.driver.core.LocalDate} representation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public enum LocalDateToCassandraLocalDateConverter
|
||||
implements Converter<LocalDate, com.datastax.driver.core.LocalDate> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public com.datastax.driver.core.LocalDate convert(LocalDate source) {
|
||||
return com.datastax.driver.core.LocalDate.fromYearMonthDay(source.getYear(), source.getMonthValue(),
|
||||
source.getDayOfMonth());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple singleton to convert {@link Long}s to their {@link LocalTime} representation.
|
||||
*
|
||||
@@ -130,7 +94,7 @@ public abstract class CassandraThreeTenBackPortConverters {
|
||||
* @since 2.1
|
||||
*/
|
||||
@WritingConverter
|
||||
@CassandraType(type = Name.TIME)
|
||||
@CassandraType(type = CassandraSimpleTypeHolder.Name.TIME)
|
||||
public enum LocalTimeToMillisOfDayConverter implements Converter<LocalTime, Long> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@@ -15,28 +15,20 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.CodecRegistry;
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.TupleValue;
|
||||
import com.datastax.oss.driver.api.core.data.TupleValue;
|
||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||
|
||||
/**
|
||||
* {@link CassandraValueProvider} to read property values from a {@link TupleValue}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.1
|
||||
* @deprecated since 3.0, use {@link TupleValueProvider} directly.
|
||||
*/
|
||||
public class CassandraTupleValueProvider implements CassandraValueProvider {
|
||||
|
||||
private final CodecRegistry codecRegistry;
|
||||
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
|
||||
private final TupleValue tupleValue;
|
||||
@Deprecated
|
||||
public class CassandraTupleValueProvider extends TupleValueProvider {
|
||||
|
||||
/**
|
||||
* Create a new {@link CassandraTupleValueProvider} with the given {@link TupleValue} and
|
||||
@@ -48,40 +40,6 @@ public class CassandraTupleValueProvider implements CassandraValueProvider {
|
||||
*/
|
||||
public CassandraTupleValueProvider(TupleValue tupleValue, CodecRegistry codecRegistry,
|
||||
SpELExpressionEvaluator evaluator) {
|
||||
|
||||
Assert.notNull(tupleValue, "TupleValue must not be null");
|
||||
Assert.notNull(codecRegistry, "CodecRegistry must not be null");
|
||||
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null");
|
||||
|
||||
this.tupleValue = tupleValue;
|
||||
this.codecRegistry = codecRegistry;
|
||||
this.evaluator = evaluator;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T getPropertyValue(CassandraPersistentProperty property) {
|
||||
|
||||
String spelExpression = property.getSpelExpression();
|
||||
|
||||
if (spelExpression != null) {
|
||||
return evaluator.evaluate(spelExpression);
|
||||
}
|
||||
|
||||
int ordinal = property.getRequiredOrdinal();
|
||||
DataType elementType = tupleValue.getType().getComponentTypes().get(ordinal);
|
||||
|
||||
return tupleValue.get(ordinal, codecRegistry.codecFor(elementType));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.convert.CassandraValueProvider#hasProperty(org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasProperty(CassandraPersistentProperty property) {
|
||||
return this.tupleValue.getType().getComponentTypes().size() >= property.getRequiredOrdinal();
|
||||
super(tupleValue, evaluator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,47 +15,32 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.CodecRegistry;
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.UDTValue;
|
||||
import com.datastax.oss.driver.api.core.data.UdtValue;
|
||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||
|
||||
/**
|
||||
* {@link CassandraValueProvider} to read property values from a {@link UDTValue}.
|
||||
* {@link CassandraValueProvider} to read property values from a {@link UdtValue}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 1.5
|
||||
* @deprecated since 3.0, use {@link UdtValueProvider} directly.
|
||||
*/
|
||||
public class CassandraUDTValueProvider implements CassandraValueProvider {
|
||||
|
||||
private final UDTValue udtValue;
|
||||
|
||||
private final CodecRegistry codecRegistry;
|
||||
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
@Deprecated
|
||||
public class CassandraUDTValueProvider extends UdtValueProvider {
|
||||
|
||||
/**
|
||||
* Create a new {@link CassandraUDTValueProvider} with the given {@link UDTValue} and {@link SpELExpressionEvaluator}.
|
||||
* Create a new {@link CassandraUDTValueProvider} with the given {@link UdtValue} and {@link SpELExpressionEvaluator}.
|
||||
*
|
||||
* @param udtValue must not be {@literal null}.
|
||||
* @param codecRegistry must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
* @since 2.1
|
||||
*/
|
||||
public CassandraUDTValueProvider(UDTValue udtValue, CodecRegistry codecRegistry, SpELExpressionEvaluator evaluator) {
|
||||
|
||||
Assert.notNull(udtValue, "UDTValue must not be null");
|
||||
Assert.notNull(codecRegistry, "CodecRegistry must not be null");
|
||||
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null");
|
||||
|
||||
this.udtValue = udtValue;
|
||||
this.codecRegistry = codecRegistry;
|
||||
this.evaluator = evaluator;
|
||||
public CassandraUDTValueProvider(UdtValue udtValue, CodecRegistry codecRegistry, SpELExpressionEvaluator evaluator) {
|
||||
super(udtValue, evaluator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,38 +50,11 @@ public class CassandraUDTValueProvider implements CassandraValueProvider {
|
||||
* @param udtValue must not be {@literal null}.
|
||||
* @param codecRegistry must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
* @deprecated since 2.1, use {@link #CassandraUDTValueProvider(UDTValue, CodecRegistry, SpELExpressionEvaluator)}
|
||||
* @deprecated since 2.1, use {@link #CassandraUDTValueProvider(UdtValue, CodecRegistry, SpELExpressionEvaluator)}
|
||||
*/
|
||||
@Deprecated
|
||||
public CassandraUDTValueProvider(UDTValue udtValue, CodecRegistry codecRegistry,
|
||||
public CassandraUDTValueProvider(UdtValue udtValue, CodecRegistry codecRegistry,
|
||||
DefaultSpELExpressionEvaluator evaluator) {
|
||||
|
||||
this(udtValue, codecRegistry, (SpELExpressionEvaluator) evaluator);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T getPropertyValue(CassandraPersistentProperty property) {
|
||||
|
||||
String spelExpression = property.getSpelExpression();
|
||||
|
||||
if (spelExpression != null) {
|
||||
return this.evaluator.evaluate(spelExpression);
|
||||
}
|
||||
|
||||
String name = property.getRequiredColumnName().toCql();
|
||||
DataType fieldType = this.udtValue.getType().getFieldType(name);
|
||||
|
||||
return this.udtValue.get(name, this.codecRegistry.codecFor(fieldType));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.convert.CassandraValueProvider#hasProperty(org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasProperty(CassandraPersistentProperty property) {
|
||||
return this.udtValue.getType().contains(property.getRequiredColumnName().toCql());
|
||||
super(udtValue, evaluator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,20 +60,15 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.datastax.driver.core.CodecRegistry;
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.TupleType;
|
||||
import com.datastax.driver.core.TupleValue;
|
||||
import com.datastax.driver.core.TypeCodec;
|
||||
import com.datastax.driver.core.UDTValue;
|
||||
import com.datastax.driver.core.UserType;
|
||||
import com.datastax.driver.core.querybuilder.Clause;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
import com.datastax.driver.core.querybuilder.Update;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
import com.datastax.oss.driver.api.core.data.TupleValue;
|
||||
import com.datastax.oss.driver.api.core.data.UdtValue;
|
||||
import com.datastax.oss.driver.api.core.type.DataType;
|
||||
import com.datastax.oss.driver.api.core.type.TupleType;
|
||||
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
||||
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
|
||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||
|
||||
/**
|
||||
* {@link CassandraConverter} that uses a {@link MappingContext} to do sophisticated mapping of domain objects to
|
||||
@@ -178,11 +173,11 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
private <S> ConvertingPropertyAccessor<S> newConvertingPropertyAccessor(S source,
|
||||
CassandraPersistentEntity<?> entity) {
|
||||
|
||||
PersistentPropertyAccessor propertyAccessor = source instanceof PersistentPropertyAccessor
|
||||
PersistentPropertyAccessor<S> propertyAccessor = source instanceof PersistentPropertyAccessor
|
||||
? (PersistentPropertyAccessor) source
|
||||
: entity.getPropertyAccessor(source);
|
||||
|
||||
return new ConvertingPropertyAccessor<>(propertyAccessor, getConversionService());
|
||||
return new ConvertingPropertyAccessor<S>(propertyAccessor, getConversionService());
|
||||
}
|
||||
|
||||
private <S> PersistentEntityParameterValueProvider<CassandraPersistentProperty> newParameterValueProvider(
|
||||
@@ -233,10 +228,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
return (R) row;
|
||||
}
|
||||
|
||||
if (com.datastax.oss.driver.api.core.cql.Row.class.isAssignableFrom(rawType)) {
|
||||
return (R) row;
|
||||
}
|
||||
|
||||
if (getCustomConversions().hasCustomReadTarget(Row.class, rawType)
|
||||
|| getConversionService().canConvert(Row.class, rawType)) {
|
||||
|
||||
@@ -256,32 +247,23 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
CassandraPersistentEntity<R> persistentEntity = (CassandraPersistentEntity<R>) getMappingContext()
|
||||
.getRequiredPersistentEntity(typeInfo);
|
||||
|
||||
if (row instanceof Row) {
|
||||
return readEntityFromRow(persistentEntity, row);
|
||||
}
|
||||
return readEntityFromRow(persistentEntity, row);
|
||||
|
||||
return readEntityFromRow(persistentEntity, (com.datastax.oss.driver.api.core.cql.Row) row);
|
||||
}
|
||||
|
||||
private <S> S readEntityFromRow(CassandraPersistentEntity<S> entity, com.datastax.oss.driver.api.core.cql.Row row) {
|
||||
return doReadEntity(entity, row, expressionEvaluator -> new RowValueProvider(row, expressionEvaluator));
|
||||
}
|
||||
|
||||
private <S> S readEntityFromRow(CassandraPersistentEntity<S> entity, Row row) {
|
||||
return doReadEntity(entity, row,
|
||||
expressionEvaluator -> new BasicCassandraRowValueProvider(row, getCodecRegistry(), expressionEvaluator));
|
||||
return doReadEntity(entity, row, expressionEvaluator -> new RowValueProvider(row, expressionEvaluator));
|
||||
}
|
||||
|
||||
private <S> S readEntityFromTuple(CassandraPersistentEntity<S> entity, TupleValue tupleValue) {
|
||||
|
||||
return doReadEntity(entity, tupleValue,
|
||||
expressionEvaluator -> new CassandraTupleValueProvider(tupleValue, getCodecRegistry(), expressionEvaluator));
|
||||
expressionEvaluator -> new TupleValueProvider(tupleValue, expressionEvaluator));
|
||||
}
|
||||
|
||||
private <S> S readEntityFromUdt(CassandraPersistentEntity<S> entity, UDTValue udtValue) {
|
||||
private <S> S readEntityFromUdt(CassandraPersistentEntity<S> entity, UdtValue udtValue) {
|
||||
|
||||
return doReadEntity(entity, udtValue,
|
||||
expressionEvaluator -> new CassandraUDTValueProvider(udtValue, getCodecRegistry(), expressionEvaluator));
|
||||
return doReadEntity(entity, udtValue, expressionEvaluator -> new UdtValueProvider(udtValue, expressionEvaluator));
|
||||
}
|
||||
|
||||
private <S> S doReadEntity(CassandraPersistentEntity<S> entity, Object value,
|
||||
@@ -376,26 +358,20 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
throw new MappingException("No mapping metadata found for " + source.getClass());
|
||||
}
|
||||
|
||||
if (sink instanceof Map) {
|
||||
writeMapFromWrapper(newConvertingPropertyAccessor(source, entity), (Map<String, Object>) sink, entity);
|
||||
} else if (sink instanceof Insert) {
|
||||
writeInsertFromWrapper(newConvertingPropertyAccessor(source, entity), (Insert) sink, entity);
|
||||
} else if (sink instanceof Update) {
|
||||
writeUpdateFromWrapper(newConvertingPropertyAccessor(source, entity), (Update) sink, entity);
|
||||
} else if (sink instanceof Select.Where) {
|
||||
writeSelectWhereFromObject(source, (Select.Where) sink, entity);
|
||||
} else if (sink instanceof Delete.Where) {
|
||||
writeDeleteWhereFromObject(source, (Delete.Where) sink, entity);
|
||||
if (sink instanceof Where) {
|
||||
writeWhereFromObject(source, (Where) sink, entity);
|
||||
} else if (sink instanceof Map) {
|
||||
writeMapFromWrapper(newConvertingPropertyAccessor(source, entity), (Map<CqlIdentifier, Object>) sink, entity);
|
||||
} else if (sink instanceof TupleValue) {
|
||||
writeTupleValue(newConvertingPropertyAccessor(source, entity), (TupleValue) sink, entity);
|
||||
} else if (sink instanceof UDTValue) {
|
||||
writeUDTValue(newConvertingPropertyAccessor(source, entity), (UDTValue) sink, entity);
|
||||
} else if (sink instanceof UdtValue) {
|
||||
writeUDTValue(newConvertingPropertyAccessor(source, entity), (UdtValue) sink, entity);
|
||||
} else {
|
||||
throw new MappingException(String.format("Unknown write target [%s]", ObjectUtils.nullSafeClassName(sink)));
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMapFromWrapper(ConvertingPropertyAccessor accessor, Map<String, Object> insert,
|
||||
private void writeMapFromWrapper(ConvertingPropertyAccessor<?> accessor, Map<CqlIdentifier, Object> sink,
|
||||
CassandraPersistentEntity<?> entity) {
|
||||
|
||||
for (CassandraPersistentProperty property : entity) {
|
||||
@@ -406,46 +382,10 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
log.debug("doWithProperties Property.type {}, Property.value {}", property.getType().getName(), value);
|
||||
}
|
||||
|
||||
if (property.isCompositePrimaryKey()) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Property is a compositeKey");
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CassandraPersistentEntity<?> compositePrimaryKey = getMappingContext().getRequiredPersistentEntity(property);
|
||||
|
||||
writeMapFromWrapper(newConvertingPropertyAccessor(value, compositePrimaryKey), insert, compositePrimaryKey);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding map.entry [{}] - [{}]", property.getRequiredColumnName().toCql(), value);
|
||||
}
|
||||
|
||||
insert.put(property.getRequiredColumnName().toCql(), value);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeInsertFromWrapper(ConvertingPropertyAccessor propertyAccessor, Insert insert,
|
||||
CassandraPersistentEntity<?> entity) {
|
||||
|
||||
for (CassandraPersistentProperty property : entity) {
|
||||
|
||||
if (!property.isWritable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object value = getWriteValue(property, propertyAccessor);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("doWithProperties Property.type {}, Property.value {}", property.getType().getName(), value);
|
||||
}
|
||||
|
||||
if (property.isCompositePrimaryKey()) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -458,88 +398,20 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
CassandraPersistentEntity<?> compositePrimaryKey = getMappingContext().getRequiredPersistentEntity(property);
|
||||
|
||||
writeInsertFromWrapper(newConvertingPropertyAccessor(value, compositePrimaryKey), insert, compositePrimaryKey);
|
||||
writeMapFromWrapper(newConvertingPropertyAccessor(value, compositePrimaryKey), sink, compositePrimaryKey);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding insert.value [{}] - [{}]", property.getRequiredColumnName().toCql(), value);
|
||||
log.debug("Adding map.entry [{}] - [{}]", property.getRequiredColumnName(), value);
|
||||
}
|
||||
|
||||
insert.value(property.getRequiredColumnName().toCql(), value);
|
||||
sink.put(property.getRequiredColumnName(), value);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeUpdateFromWrapper(ConvertingPropertyAccessor propertyAccessor, Update update,
|
||||
CassandraPersistentEntity<?> entity) {
|
||||
|
||||
for (CassandraPersistentProperty property : entity) {
|
||||
|
||||
if (!property.isWritable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object value = getWriteValue(property, propertyAccessor);
|
||||
|
||||
if (property.isCompositePrimaryKey()) {
|
||||
|
||||
CassandraPersistentEntity<?> compositePrimaryKey = getMappingContext().getRequiredPersistentEntity(property);
|
||||
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
writeUpdateFromWrapper(newConvertingPropertyAccessor(value, compositePrimaryKey), update, compositePrimaryKey);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isPrimaryKeyPart(property)) {
|
||||
update.where(QueryBuilder.eq(property.getRequiredColumnName().toCql(), value));
|
||||
} else {
|
||||
update.with(QueryBuilder.set(property.getRequiredColumnName().toCql(), value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the property is part of the primary key.
|
||||
*
|
||||
* @param property {@link CassandraPersistentProperty} to evaluate.
|
||||
* @return a boolean value indicating whether the given property is party of a primary key.
|
||||
*/
|
||||
private boolean isPrimaryKeyPart(CassandraPersistentProperty property) {
|
||||
return property.isCompositePrimaryKey() || property.isPrimaryKeyColumn() || property.isIdProperty();
|
||||
}
|
||||
|
||||
private void writeSelectWhereFromObject(Object object, Select.Where where, CassandraPersistentEntity<?> entity) {
|
||||
getWhereClauses(object, entity).forEach(where::and);
|
||||
}
|
||||
|
||||
private void writeDeleteWhereFromObject(Object object, Delete.Where where, CassandraPersistentEntity<?> entity) {
|
||||
getWhereClauses(object, entity).forEach(where::and);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object extractId(Object source, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
if (ClassUtils.isAssignableValue(entity.getType(), source)) {
|
||||
return getId(source, entity);
|
||||
} else if (source instanceof MapId) {
|
||||
return source;
|
||||
} else if (source instanceof MapIdentifiable) {
|
||||
return ((MapIdentifiable) source).getMapId();
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
private Collection<Clause> getWhereClauses(Object source, CassandraPersistentEntity<?> entity) {
|
||||
private void writeWhereFromObject(Object source, Where sink, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
Assert.notNull(source, "Id source must not be null");
|
||||
|
||||
@@ -560,7 +432,8 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
? getMappingContext().getRequiredPersistentEntity(compositeIdProperty)
|
||||
: entity;
|
||||
|
||||
return getWhereClauses(MapId.class.cast(id), whereEntity);
|
||||
writeWhere(MapId.class.cast(id), sink, whereEntity);
|
||||
return;
|
||||
}
|
||||
|
||||
if (idProperty == null) {
|
||||
@@ -578,21 +451,33 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
CassandraPersistentEntity<?> compositePrimaryKey = getMappingContext()
|
||||
.getRequiredPersistentEntity(compositeIdProperty);
|
||||
|
||||
return getWhereClauses(newConvertingPropertyAccessor(id, compositePrimaryKey), compositePrimaryKey);
|
||||
writeWhere(newConvertingPropertyAccessor(id, compositePrimaryKey), sink, compositePrimaryKey);
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?> targetType = getTargetType(idProperty);
|
||||
|
||||
return Collections.singleton(QueryBuilder.eq(idProperty.getRequiredColumnName().toCql(),
|
||||
getPotentiallyConvertedSimpleValue(id, targetType)));
|
||||
sink.put(idProperty.getRequiredColumnName(), getPotentiallyConvertedSimpleValue(id, targetType));
|
||||
}
|
||||
|
||||
private Collection<Clause> getWhereClauses(MapId id, CassandraPersistentEntity<?> entity) {
|
||||
@Nullable
|
||||
private Object extractId(Object source, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
if (ClassUtils.isAssignableValue(entity.getType(), source)) {
|
||||
return getId(source, entity);
|
||||
} else if (source instanceof MapId) {
|
||||
return source;
|
||||
} else if (source instanceof MapIdentifiable) {
|
||||
return ((MapIdentifiable) source).getMapId();
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
private void writeWhere(MapId id, Where sink, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
Assert.notNull(id, "MapId must not be null");
|
||||
|
||||
Collection<Clause> clauses = new ArrayList<>();
|
||||
|
||||
for (Entry<String, Object> entry : id.entrySet()) {
|
||||
|
||||
CassandraPersistentProperty persistentProperty = entity.getPersistentProperty(entry.getKey());
|
||||
@@ -604,29 +489,23 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
Object writeValue = getWriteValue(entry.getValue(), persistentProperty.getTypeInformation());
|
||||
|
||||
clauses.add(QueryBuilder.eq(persistentProperty.getRequiredColumnName().toCql(), writeValue));
|
||||
sink.put(persistentProperty.getRequiredColumnName(), writeValue);
|
||||
}
|
||||
|
||||
return clauses;
|
||||
}
|
||||
|
||||
private Collection<Clause> getWhereClauses(ConvertingPropertyAccessor accessor, CassandraPersistentEntity<?> entity) {
|
||||
private void writeWhere(ConvertingPropertyAccessor<?> accessor, Where sink, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
Assert.isTrue(entity.isCompositePrimaryKey(),
|
||||
String.format("Entity [%s] is not a composite primary key", entity.getName()));
|
||||
|
||||
Collection<Clause> clauses = new ArrayList<>();
|
||||
|
||||
for (CassandraPersistentProperty property : entity) {
|
||||
TypeCodec<Object> codec = getCodec(property);
|
||||
Object value = accessor.getProperty(property, codec.getJavaType().getRawType());
|
||||
clauses.add(QueryBuilder.eq(property.getRequiredColumnName().toCql(), value));
|
||||
sink.put(property.getRequiredColumnName(), value);
|
||||
}
|
||||
|
||||
return clauses;
|
||||
}
|
||||
|
||||
private void writeTupleValue(ConvertingPropertyAccessor propertyAccessor, TupleValue tupleValue,
|
||||
private void writeTupleValue(ConvertingPropertyAccessor<?> propertyAccessor, TupleValue tupleValue,
|
||||
CassandraPersistentEntity<?> entity) {
|
||||
|
||||
for (CassandraPersistentProperty property : entity) {
|
||||
@@ -647,7 +526,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
}
|
||||
}
|
||||
|
||||
private void writeUDTValue(ConvertingPropertyAccessor propertyAccessor, UDTValue udtValue,
|
||||
private void writeUDTValue(ConvertingPropertyAccessor<?> propertyAccessor, UdtValue udtValue,
|
||||
CassandraPersistentEntity<?> entity) {
|
||||
|
||||
for (CassandraPersistentProperty property : entity) {
|
||||
@@ -664,12 +543,12 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Adding udt.value [{}] - [{}]", property.getRequiredColumnName().toCql(), value);
|
||||
log.debug("Adding udt.value [{}] - [{}]", property.getRequiredColumnName(), value);
|
||||
}
|
||||
|
||||
TypeCodec<Object> typeCodec = getCodec(property);
|
||||
|
||||
udtValue.set(property.getRequiredColumnName().toCql(), value, typeCodec);
|
||||
udtValue.set(property.getRequiredColumnName().toString(), value, typeCodec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,7 +559,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
Assert.notNull(object, "Object instance must not be null");
|
||||
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
||||
|
||||
ConvertingPropertyAccessor propertyAccessor = newConvertingPropertyAccessor(object, entity);
|
||||
ConvertingPropertyAccessor<?> propertyAccessor = newConvertingPropertyAccessor(object, entity);
|
||||
|
||||
Assert.isTrue(entity.getType().isAssignableFrom(object.getClass()),
|
||||
String.format("Given instance of type [%s] is not compatible with expected type [%s]",
|
||||
@@ -739,7 +618,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
}
|
||||
|
||||
DataType dataType = getMappingContext().getDataType(property);
|
||||
if (dataType instanceof UserType || dataType instanceof TupleType) {
|
||||
if (dataType instanceof UserDefinedType || dataType instanceof TupleType) {
|
||||
return property.getType();
|
||||
}
|
||||
|
||||
@@ -830,7 +709,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
if (entity.isUserDefinedType()) {
|
||||
|
||||
UDTValue udtValue = entity.getUserType().newValue();
|
||||
UdtValue udtValue = entity.getUserType().newValue();
|
||||
|
||||
write(value, udtValue, entity);
|
||||
|
||||
@@ -999,13 +878,13 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
}
|
||||
}
|
||||
|
||||
if (value instanceof UDTValue) {
|
||||
if (value instanceof UdtValue) {
|
||||
|
||||
BasicCassandraPersistentEntity<?> udtEntity = getMappingContext()
|
||||
.getPersistentEntity(typeInformation.getRequiredActualType());
|
||||
|
||||
if (udtEntity != null && udtEntity.isUserDefinedType()) {
|
||||
return readEntityFromUdt(udtEntity, (UDTValue) value);
|
||||
return readEntityFromUdt(udtEntity, (UdtValue) value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1039,7 +918,7 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
|
||||
if (entity != null && entity.isUserDefinedType()) {
|
||||
for (Object element : source) {
|
||||
collection.add(readEntityFromUdt(entity, (UDTValue) element));
|
||||
collection.add(readEntityFromUdt(entity, (UdtValue) element));
|
||||
}
|
||||
|
||||
} else if (entity != null && entity.isTupleType()) {
|
||||
@@ -1076,7 +955,6 @@ public class MappingCassandraConverter extends AbstractCassandraConverter
|
||||
* @param targetType must not be {@literal null}.
|
||||
* @return the converted {@link Collection} or array, will never be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private Object readMapInternal(Map<Object, Object> source, TypeInformation<?> targetType) {
|
||||
|
||||
Assert.notNull(targetType, "Target type must not be null");
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
@@ -49,6 +48,8 @@ import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* Map {@link org.springframework.data.cassandra.core.query.Query} to CQL-specific data types.
|
||||
*
|
||||
@@ -85,7 +86,7 @@ public class QueryMapper {
|
||||
* @return the configured {@link CassandraConverter}.
|
||||
* @see org.springframework.data.cassandra.core.convert.CassandraConverter
|
||||
*/
|
||||
protected CassandraConverter getConverter() {
|
||||
public CassandraConverter getConverter() {
|
||||
return this.converter;
|
||||
}
|
||||
|
||||
@@ -185,7 +186,7 @@ public class QueryMapper {
|
||||
CassandraPersistentEntity<?> primaryKeyEntity = mappingContext.getRequiredPersistentEntity(property);
|
||||
addColumns(primaryKeyEntity, selectors);
|
||||
} else {
|
||||
selectors.add(ColumnSelector.from(property.getRequiredColumnName().toCql()));
|
||||
selectors.add(ColumnSelector.from(property.getRequiredColumnName()));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -234,7 +235,7 @@ public class QueryMapper {
|
||||
* @param entity must not be {@literal null}.
|
||||
* @return the mapped column names.
|
||||
*/
|
||||
public List<String> getMappedColumnNames(Columns columns, CassandraPersistentEntity<?> entity) {
|
||||
public List<CqlIdentifier> getMappedColumnNames(Columns columns, CassandraPersistentEntity<?> entity) {
|
||||
|
||||
Assert.notNull(columns, "Columns must not be null");
|
||||
Assert.notNull(entity, "CassandraPersistentEntity must not be null");
|
||||
@@ -243,7 +244,7 @@ public class QueryMapper {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<String> columnNames = new ArrayList<>();
|
||||
List<CqlIdentifier> columnNames = new ArrayList<>();
|
||||
|
||||
Set<PersistentProperty<?>> seen = new HashSet<>();
|
||||
|
||||
@@ -254,7 +255,7 @@ public class QueryMapper {
|
||||
field.getProperty().ifPresent(seen::add);
|
||||
|
||||
columns.getSelector(column).filter(selector -> selector instanceof ColumnSelector).ifPresent(
|
||||
columnSelector -> getCqlIdentifier(column, field).map(CqlIdentifier::toCql).ifPresent(columnNames::add));
|
||||
columnSelector -> getCqlIdentifier(column, field).ifPresent(columnNames::add));
|
||||
}
|
||||
|
||||
if (columns.isEmpty()) {
|
||||
@@ -266,7 +267,7 @@ public class QueryMapper {
|
||||
}
|
||||
|
||||
if (seen.add(property)) {
|
||||
columnNames.add(property.getRequiredColumnName().toCql());
|
||||
columnNames.add(property.getRequiredColumnName());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -292,7 +293,7 @@ public class QueryMapper {
|
||||
Field field = createPropertyField(entity, columnName);
|
||||
|
||||
Order mappedOrder = getCqlIdentifier(columnName, field)
|
||||
.map(cqlIdentifier -> new Order(order.getDirection(), cqlIdentifier.toCql())).orElse(order);
|
||||
.map(cqlIdentifier -> new Order(order.getDirection(), cqlIdentifier.toString())).orElse(order);
|
||||
|
||||
mappedOrders.add(mappedOrder);
|
||||
}
|
||||
@@ -317,7 +318,7 @@ public class QueryMapper {
|
||||
}
|
||||
|
||||
if (column.getColumnName().isPresent()) {
|
||||
return column.getColumnName().map(CqlIdentifier::of);
|
||||
return column.getColumnName().map(CqlIdentifier::fromCql);
|
||||
}
|
||||
|
||||
return column.getCqlIdentifier();
|
||||
|
||||
@@ -15,38 +15,40 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.cassandra.core.cql.CqlIdentifier;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.CodecRegistry;
|
||||
import com.datastax.driver.core.ColumnDefinitions;
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.DataType.Name;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.TypeCodec;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.cql.ColumnDefinition;
|
||||
import com.datastax.oss.driver.api.core.cql.ColumnDefinitions;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
import com.datastax.oss.driver.api.core.type.DataType;
|
||||
import com.datastax.oss.driver.api.core.type.ListType;
|
||||
import com.datastax.oss.driver.api.core.type.MapType;
|
||||
import com.datastax.oss.driver.api.core.type.SetType;
|
||||
import com.datastax.oss.driver.api.core.type.TupleType;
|
||||
import com.datastax.oss.driver.api.core.type.UserDefinedType;
|
||||
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
|
||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||
|
||||
/**
|
||||
* Helpful class to read a column's value from a row, with possible type conversion.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Antoine Toulme
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ColumnReader {
|
||||
class RowReader {
|
||||
|
||||
private final Row row;
|
||||
private final com.datastax.oss.driver.api.core.cql.Row row;
|
||||
|
||||
private final CodecRegistry codecRegistry;
|
||||
|
||||
private final ColumnDefinitions columns;
|
||||
|
||||
public ColumnReader(Row row, CodecRegistry codecRegistry) {
|
||||
public RowReader(Row row) {
|
||||
|
||||
this.row = row;
|
||||
this.codecRegistry = codecRegistry;
|
||||
this.codecRegistry = row.codecRegistry();
|
||||
this.columns = row.getColumnDefinitions();
|
||||
}
|
||||
|
||||
@@ -55,7 +57,7 @@ public class ColumnReader {
|
||||
*/
|
||||
@Nullable
|
||||
public Object get(CqlIdentifier columnName) {
|
||||
return get(columnName.toCql());
|
||||
return get(columnName.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,18 +81,18 @@ public class ColumnReader {
|
||||
return null;
|
||||
}
|
||||
|
||||
DataType type = columns.getType(columnIndex);
|
||||
ColumnDefinition type = columns.get(columnIndex);
|
||||
|
||||
if (type.isCollection()) {
|
||||
return getCollection(columnIndex, type);
|
||||
if (type.getType() instanceof ListType || type.getType() instanceof SetType || type.getType() instanceof MapType) {
|
||||
return getCollection(columnIndex, type.getType());
|
||||
}
|
||||
|
||||
if (Name.TUPLE.equals(type.getName())) {
|
||||
if (type instanceof TupleType) {
|
||||
return row.getTupleValue(columnIndex);
|
||||
}
|
||||
|
||||
if (Name.UDT.equals(type.getName())) {
|
||||
return row.getUDTValue(columnIndex);
|
||||
if (type instanceof UserDefinedType) {
|
||||
return row.getUdtValue(columnIndex);
|
||||
}
|
||||
|
||||
return row.getObject(columnIndex);
|
||||
@@ -103,7 +105,7 @@ public class ColumnReader {
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T get(CqlIdentifier columnName, Class<T> requestedType) {
|
||||
return get(columnName.toCql(), requestedType);
|
||||
return get(columnName.toString(), requestedType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,26 +134,27 @@ public class ColumnReader {
|
||||
@Nullable
|
||||
private Object getCollection(int index, DataType type) {
|
||||
|
||||
List<DataType> collectionTypes = type.getTypeArguments();
|
||||
|
||||
// List/Set
|
||||
if (collectionTypes.size() == 1) {
|
||||
|
||||
DataType valueType = collectionTypes.get(0);
|
||||
if (type instanceof ListType) {
|
||||
|
||||
ListType listType = (ListType) type;
|
||||
DataType valueType = listType.getElementType();
|
||||
TypeCodec<Object> typeCodec = codecRegistry.codecFor(valueType);
|
||||
|
||||
if (type.equals(DataType.list(valueType))) {
|
||||
return row.getList(index, typeCodec.getJavaType().getRawType());
|
||||
}
|
||||
return row.getList(index, typeCodec.getJavaType().getRawType());
|
||||
}
|
||||
|
||||
if (type.equals(DataType.set(valueType))) {
|
||||
return row.getSet(index, typeCodec.getJavaType().getRawType());
|
||||
}
|
||||
if (type instanceof SetType) {
|
||||
|
||||
SetType setType = (SetType) type;
|
||||
DataType valueType = setType.getElementType();
|
||||
TypeCodec<Object> typeCodec = codecRegistry.codecFor(valueType);
|
||||
|
||||
return row.getList(index, typeCodec.getJavaType().getRawType());
|
||||
}
|
||||
|
||||
// Map
|
||||
if (type.getName() == Name.MAP) {
|
||||
if (type instanceof MapType) {
|
||||
|
||||
return row.getObject(index);
|
||||
}
|
||||
|
||||
@@ -160,7 +163,7 @@ public class ColumnReader {
|
||||
|
||||
private int getColumnIndex(String columnName) {
|
||||
|
||||
int index = columns.getIndexOf(columnName);
|
||||
int index = columns.firstIndexOf(columnName);
|
||||
|
||||
Assert.isTrue(index > -1, String.format("Column [%s] does not exist in table", columnName));
|
||||
|
||||
@@ -172,6 +175,6 @@ public class ColumnReader {
|
||||
}
|
||||
|
||||
public boolean contains(CqlIdentifier columnName) {
|
||||
return row.getColumnDefinitions().contains(columnName.toCql());
|
||||
return row.getColumnDefinitions().contains(columnName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||
|
||||
/**
|
||||
* {@link CassandraValueProvider} to read property values from a {@link Row}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
*/
|
||||
public class RowValueProvider implements CassandraValueProvider {
|
||||
|
||||
private final RowReader reader;
|
||||
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
|
||||
/**
|
||||
* Create a new {@link RowValueProvider} with the given {@link Row}, {@link CodecRegistry} and
|
||||
* {@link SpELExpressionEvaluator}.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param codecRegistry must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
*/
|
||||
public RowValueProvider(Row source, SpELExpressionEvaluator evaluator) {
|
||||
|
||||
Assert.notNull(source, "Source Row must not be null");
|
||||
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null");
|
||||
|
||||
this.reader = new RowReader(source);
|
||||
this.evaluator = evaluator;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getPropertyValue(CassandraPersistentProperty property) {
|
||||
|
||||
String spelExpression = property.getSpelExpression();
|
||||
|
||||
return spelExpression != null ? this.evaluator.evaluate(spelExpression)
|
||||
: (T) this.reader.get(property.getRequiredColumnName());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.convert.CassandraValueProvider#hasProperty(org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasProperty(CassandraPersistentProperty property) {
|
||||
|
||||
Assert.notNull(property, "CassandraPersistentProperty must not be null");
|
||||
|
||||
return this.reader.contains(property.getRequiredColumnName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.data.TupleValue;
|
||||
import com.datastax.oss.driver.api.core.type.DataType;
|
||||
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
|
||||
|
||||
/**
|
||||
* {@link CassandraValueProvider} to read property values from a {@link TupleValue}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
*/
|
||||
public class TupleValueProvider implements CassandraValueProvider {
|
||||
|
||||
private final CodecRegistry codecRegistry;
|
||||
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
|
||||
private final TupleValue tupleValue;
|
||||
|
||||
/**
|
||||
* Create a new {@link TupleValueProvider} with the given {@link TupleValue} and {@link SpELExpressionEvaluator}.
|
||||
*
|
||||
* @param tupleValue must not be {@literal null}.
|
||||
* @param codecRegistry must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
*/
|
||||
public TupleValueProvider(TupleValue tupleValue, SpELExpressionEvaluator evaluator) {
|
||||
|
||||
Assert.notNull(tupleValue, "TupleValue must not be null");
|
||||
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null");
|
||||
|
||||
this.tupleValue = tupleValue;
|
||||
this.codecRegistry = tupleValue.codecRegistry();
|
||||
this.evaluator = evaluator;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T getPropertyValue(CassandraPersistentProperty property) {
|
||||
|
||||
String spelExpression = property.getSpelExpression();
|
||||
|
||||
if (spelExpression != null) {
|
||||
return evaluator.evaluate(spelExpression);
|
||||
}
|
||||
|
||||
int ordinal = property.getRequiredOrdinal();
|
||||
DataType elementType = tupleValue.getType().getComponentTypes().get(ordinal);
|
||||
|
||||
return tupleValue.get(ordinal, codecRegistry.codecFor(elementType));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.convert.CassandraValueProvider#hasProperty(org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasProperty(CassandraPersistentProperty property) {
|
||||
return this.tupleValue.getType().getComponentTypes().size() >= property.getRequiredOrdinal();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.data.UdtValue;
|
||||
|
||||
/**
|
||||
* {@link CassandraValueProvider} to read property values from a {@link UdtValue}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
*/
|
||||
public class UdtValueProvider implements CassandraValueProvider {
|
||||
|
||||
private final UdtValue udtValue;
|
||||
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
|
||||
/**
|
||||
* Create a new {@link UdtValueProvider} with the given {@link UDTValue} and {@link SpELExpressionEvaluator}.
|
||||
*
|
||||
* @param udtValue must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
*/
|
||||
public UdtValueProvider(UdtValue udtValue, SpELExpressionEvaluator evaluator) {
|
||||
|
||||
Assert.notNull(udtValue, "UDTValue must not be null");
|
||||
Assert.notNull(evaluator, "SpELExpressionEvaluator must not be null");
|
||||
|
||||
this.udtValue = udtValue;
|
||||
this.evaluator = evaluator;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.PropertyValueProvider#getPropertyValue(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T getPropertyValue(CassandraPersistentProperty property) {
|
||||
|
||||
String spelExpression = property.getSpelExpression();
|
||||
|
||||
if (spelExpression != null) {
|
||||
return this.evaluator.evaluate(spelExpression);
|
||||
}
|
||||
|
||||
return (T) this.udtValue.getObject(property.getRequiredColumnName());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.convert.CassandraValueProvider#hasProperty(org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasProperty(CassandraPersistentProperty property) {
|
||||
return this.udtValue.getType().contains(property.getRequiredColumnName());
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,10 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.DataType.Name;
|
||||
import com.datastax.oss.driver.api.core.type.DataType;
|
||||
import com.datastax.oss.driver.api.core.type.ListType;
|
||||
import com.datastax.oss.driver.api.core.type.SetType;
|
||||
import com.datastax.oss.protocol.internal.ProtocolConstants;
|
||||
|
||||
/**
|
||||
* Map {@link org.springframework.data.cassandra.core.query.Update} to CQL-specific data types.
|
||||
@@ -167,10 +169,10 @@ public class UpdateMapper extends QueryMapper {
|
||||
|
||||
if (collection.isEmpty()) {
|
||||
|
||||
DataType.Name dataType = field.getProperty().map(property -> getMappingContext().getDataType(property))
|
||||
.map(DataType::getName).orElse(Name.LIST);
|
||||
int protocolCode = field.getProperty().map(property -> getMappingContext().getDataType(property))
|
||||
.map(DataType::getProtocolCode).orElse(ProtocolConstants.DataType.LIST);
|
||||
|
||||
if (dataType == Name.SET) {
|
||||
if (protocolCode == ProtocolConstants.DataType.SET) {
|
||||
return new SetOp(field.getMappedKey(), Collections.emptySet());
|
||||
}
|
||||
|
||||
@@ -203,13 +205,13 @@ public class UpdateMapper extends QueryMapper {
|
||||
|
||||
DataType dataType = getMappingContext().getDataType(field.getProperty().get());
|
||||
|
||||
if (dataType.getName() == Name.SET && !(mappedValue instanceof Set)) {
|
||||
if (dataType instanceof SetType && !(mappedValue instanceof Set)) {
|
||||
Collection<Object> collection = new HashSet<>();
|
||||
collection.addAll(mappedValue);
|
||||
mappedValue = collection;
|
||||
}
|
||||
|
||||
if (dataType.getName() == Name.LIST && !(mappedValue instanceof List)) {
|
||||
if (dataType instanceof ListType && !(mappedValue instanceof List)) {
|
||||
Collection<Object> collection = new ArrayList<>();
|
||||
collection.addAll(mappedValue);
|
||||
mappedValue = collection;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.convert;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class Where extends LinkedHashMap<CqlIdentifier, Object> {}
|
||||
@@ -17,9 +17,9 @@ package org.springframework.data.cassandra.core.cql;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import com.datastax.driver.core.BoundStatement;
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.cql.BoundStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
|
||||
|
||||
/**
|
||||
* Simple adapter for {@link PreparedStatementBinder} that applies a given array of arguments.
|
||||
|
||||
@@ -23,9 +23,10 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.ResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
|
||||
/**
|
||||
* Interface specifying a basic set of CQL asynchronously executed operations. Exposes similar methods as
|
||||
@@ -42,14 +43,14 @@ import com.datastax.driver.core.Statement;
|
||||
public interface AsyncCqlOperations {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with a plain com.datastax.driver.core.Session
|
||||
// Methods dealing with a plain com.datastax.oss.driver.api.core.CqlSession
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute a CQL data access operation, implemented as callback action working on a
|
||||
* {@link com.datastax.driver.core.Session}. This allows for implementing arbitrary data access operations, within
|
||||
* Spring's managed CQL environment: that is, converting CQL
|
||||
* {@link com.datastax.driver.core.exceptions.DriverException}s into Spring's {@link DataAccessException} hierarchy.
|
||||
* Spring's managed CQL environment: that is, converting CQL {@link com.datastax.oss.driver.api.core.DriverException}s
|
||||
* into Spring's {@link DataAccessException} hierarchy.
|
||||
* <p>
|
||||
* The callback action can return a result object, for example a domain object or a collection of domain objects.
|
||||
*
|
||||
@@ -102,31 +103,30 @@ public interface AsyncCqlOperations {
|
||||
* Execute a CQL data access operation, implemented as callback action working on a CQL {@link PreparedStatement}.
|
||||
* This allows for implementing arbitrary data access operations on a single Statement, within Spring's managed CQL
|
||||
* environment: that is, participating in Spring-managed transactions and converting CQL
|
||||
* {@link com.datastax.driver.core.exceptions.DriverException}s into Spring's {@link DataAccessException} hierarchy.
|
||||
* {@link com.datastax.oss.driver.api.core.DriverException}s into Spring's {@link DataAccessException} hierarchy.
|
||||
* <p>
|
||||
* The callback action can return a result object, for example a domain object or a collection of domain objects.
|
||||
*
|
||||
* @param cql static CQL to execute, must not be {@literal null} or empty.
|
||||
* @param action callback object that specifies the action, must not be {@literal null}.
|
||||
* @return a result object returned by the action, or {@literal null}
|
||||
* @throws DataAccessException if there is any problem executing the query. TODO: Lambda-usage clashes with
|
||||
* execute(cql, PreparedStatementBinder)
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
<T> ListenableFuture<T> execute(String cql, PreparedStatementCallback<T> action) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static CQL, reading the {@link ResultSet} with a {@link ResultSetExtractor}.
|
||||
* Execute a query given static CQL, reading the {@link ResultSet} with a {@link AsyncResultSetExtractor}.
|
||||
* <p>
|
||||
* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a
|
||||
* {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array.
|
||||
*
|
||||
* @param cql static CQL to execute, must not be {@literal null} or empty.
|
||||
* @param resultSetExtractor object that will extract all rows of results, must not be {@literal null}.
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor.
|
||||
* @return an arbitrary result object, as returned by the AsyncResultSetExtractor.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #query(String, ResultSetExtractor, Object...)
|
||||
* @see #query(String, AsyncResultSetExtractor, Object...)
|
||||
*/
|
||||
<T> ListenableFuture<T> query(String cql, ResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
|
||||
<T> ListenableFuture<T> query(String cql, AsyncResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static CQL, reading the {@link ResultSet} on a per-row basis with a
|
||||
@@ -158,16 +158,16 @@ public interface AsyncCqlOperations {
|
||||
|
||||
/**
|
||||
* Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, reading the
|
||||
* {@link ResultSet} with a {@link ResultSetExtractor}.
|
||||
* {@link ResultSet} with a {@link AsyncResultSetExtractor}.
|
||||
*
|
||||
* @param cql static CQL to execute, must not be {@literal null} or empty.
|
||||
* @param resultSetExtractor object that will extract results, must not be {@literal null}.
|
||||
* @param args arguments to bind to the query (leaving it to the {@link PreparedStatement} to guess the corresponding
|
||||
* CQL type).
|
||||
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}
|
||||
* @return an arbitrary result object, as returned by the {@link AsyncResultSetExtractor}
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
<T> ListenableFuture<T> query(String cql, ResultSetExtractor<T> resultSetExtractor, Object... args)
|
||||
<T> ListenableFuture<T> query(String cql, AsyncResultSetExtractor<T> resultSetExtractor, Object... args)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
@@ -197,18 +197,18 @@ public interface AsyncCqlOperations {
|
||||
<T> ListenableFuture<List<T>> query(String cql, RowMapper<T> rowMapper, Object... args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query using a prepared statement, reading the {@link ResultSet} with a {@link ResultSetExtractor}.
|
||||
* Query using a prepared statement, reading the {@link ResultSet} with a {@link AsyncResultSetExtractor}.
|
||||
*
|
||||
* @param cql static CQL to execute, must not be {@literal null} or empty.
|
||||
* @param psb object that knows how to set values on the prepared statement. If this is {@literal null}, the CQL will
|
||||
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
|
||||
* set fetch size and other performance options.
|
||||
* @param resultSetExtractor object that will extract results, must not be {@literal null}.
|
||||
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}.
|
||||
* @return an arbitrary result object, as returned by the {@link AsyncResultSetExtractor}.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
<T> ListenableFuture<T> query(String cql, @Nullable PreparedStatementBinder psb,
|
||||
ResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
|
||||
AsyncResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given CQL to create a prepared statement from CQL and a {@link PreparedStatementBinder} implementation that
|
||||
@@ -434,7 +434,7 @@ public interface AsyncCqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForResultSet(String, Object[])
|
||||
*/
|
||||
ListenableFuture<ResultSet> queryForResultSet(String cql) throws DataAccessException;
|
||||
ListenableFuture<AsyncResultSet> queryForResultSet(String cql) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query given CQL to create a prepared statement from CQL and a list of arguments to bind to the query, expecting a
|
||||
@@ -449,10 +449,10 @@ public interface AsyncCqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForResultSet(String)
|
||||
*/
|
||||
ListenableFuture<ResultSet> queryForResultSet(String cql, Object... args) throws DataAccessException;
|
||||
ListenableFuture<AsyncResultSet> queryForResultSet(String cql, Object... args) throws DataAccessException;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.Statement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.Statement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -462,21 +462,21 @@ public interface AsyncCqlOperations {
|
||||
* @return boolean value whether the statement was applied.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
ListenableFuture<Boolean> execute(Statement statement) throws DataAccessException;
|
||||
ListenableFuture<Boolean> execute(Statement<?> statement) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static CQL, reading the {@link ResultSet} with a {@link ResultSetExtractor}.
|
||||
* Execute a query given static CQL, reading the {@link ResultSet} with a {@link AsyncResultSetExtractor}.
|
||||
* <p>
|
||||
* Uses a CQL Statement, not a {@link PreparedStatement}. If you want to execute a static query with a
|
||||
* {@link PreparedStatement}, use the overloaded {@code query} method with {@literal null} as argument array.
|
||||
*
|
||||
* @param statement static CQL {@link Statement}, must not be {@literal null}.
|
||||
* @param resultSetExtractor object that will extract all rows of results, must not be {@literal null}.
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor.
|
||||
* @return an arbitrary result object, as returned by the AsyncResultSetExtractor.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #query(String, ResultSetExtractor, Object...)
|
||||
* @see #query(String, AsyncResultSetExtractor, Object...)
|
||||
*/
|
||||
<T> ListenableFuture<T> query(Statement statement, ResultSetExtractor<T> resultSetExtractor)
|
||||
<T> ListenableFuture<T> query(Statement<?> statement, AsyncResultSetExtractor<T> resultSetExtractor)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
@@ -491,7 +491,8 @@ public interface AsyncCqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #query(String, RowCallbackHandler, Object[])
|
||||
*/
|
||||
ListenableFuture<Void> query(Statement statement, RowCallbackHandler rowCallbackHandler) throws DataAccessException;
|
||||
ListenableFuture<Void> query(Statement<?> statement, RowCallbackHandler rowCallbackHandler)
|
||||
throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static CQL, mapping each row to a Java object via a {@link RowMapper}.
|
||||
@@ -505,7 +506,7 @@ public interface AsyncCqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #query(String, RowMapper, Object[])
|
||||
*/
|
||||
<T> ListenableFuture<List<T>> query(Statement statement, RowMapper<T> rowMapper) throws DataAccessException;
|
||||
<T> ListenableFuture<List<T>> query(Statement<?> statement, RowMapper<T> rowMapper) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result {@link List}, given static CQL.
|
||||
@@ -522,7 +523,7 @@ public interface AsyncCqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForList(String, Object[])
|
||||
*/
|
||||
ListenableFuture<List<Map<String, Object>>> queryForList(Statement statement) throws DataAccessException;
|
||||
ListenableFuture<List<Map<String, Object>>> queryForList(Statement<?> statement) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result {@link List}, given static CQL.
|
||||
@@ -541,7 +542,7 @@ public interface AsyncCqlOperations {
|
||||
* @see #queryForList(String, Class, Object[])
|
||||
* @see SingleColumnRowMapper
|
||||
*/
|
||||
<T> ListenableFuture<List<T>> queryForList(Statement statement, Class<T> elementType) throws DataAccessException;
|
||||
<T> ListenableFuture<List<T>> queryForList(Statement<?> statement, Class<T> elementType) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result Map, given static CQL.
|
||||
@@ -560,7 +561,7 @@ public interface AsyncCqlOperations {
|
||||
* @see #queryForMap(String, Object[])
|
||||
* @see ColumnMapRowMapper
|
||||
*/
|
||||
ListenableFuture<Map<String, Object>> queryForMap(Statement statement) throws DataAccessException;
|
||||
ListenableFuture<Map<String, Object>> queryForMap(Statement<?> statement) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result object, given static CQL.
|
||||
@@ -580,7 +581,7 @@ public interface AsyncCqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForObject(String, Class, Object[])
|
||||
*/
|
||||
<T> ListenableFuture<T> queryForObject(Statement statement, Class<T> requiredType) throws DataAccessException;
|
||||
<T> ListenableFuture<T> queryForObject(Statement<?> statement, Class<T> requiredType) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static CQL, mapping a single result row to a Java object via a {@link RowMapper}.
|
||||
@@ -596,7 +597,7 @@ public interface AsyncCqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForObject(String, RowMapper, Object[])
|
||||
*/
|
||||
<T> ListenableFuture<T> queryForObject(Statement statement, RowMapper<T> rowMapper) throws DataAccessException;
|
||||
<T> ListenableFuture<T> queryForObject(Statement<?> statement, RowMapper<T> rowMapper) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a ResultSet, given static CQL.
|
||||
@@ -612,10 +613,10 @@ public interface AsyncCqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForResultSet(String, Object[])
|
||||
*/
|
||||
ListenableFuture<ResultSet> queryForResultSet(Statement statement) throws DataAccessException;
|
||||
ListenableFuture<AsyncResultSet> queryForResultSet(Statement<?> statement) throws DataAccessException;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.PreparedStatement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.PreparedStatement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -626,14 +627,13 @@ public interface AsyncCqlOperations {
|
||||
* @return boolean value whether the statement was applied.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
// TODO: Interferes with execute(session callback lambda)
|
||||
ListenableFuture<Boolean> execute(AsyncPreparedStatementCreator preparedStatementCreator) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a CQL data access operation, implemented as callback action working on a CQL {@link PreparedStatement}.
|
||||
* This allows for implementing arbitrary data access operations on a single {@link PreparedStatement}, within
|
||||
* Spring's managed CQL environment: that is, participating in Spring-managed transactions and converting CQL
|
||||
* {@link com.datastax.driver.core.exceptions.DriverException}s into Spring's {@link DataAccessException} hierarchy.
|
||||
* {@link com.datastax.oss.driver.api.core.DriverException}s into Spring's {@link DataAccessException} hierarchy.
|
||||
* <p>
|
||||
* The callback action can return a result object, for example a domain object or a collection of domain objects.
|
||||
*
|
||||
@@ -647,16 +647,16 @@ public interface AsyncCqlOperations {
|
||||
PreparedStatementCallback<T> action) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query using a prepared statement, reading the {@link ResultSet} with a {@link ResultSetExtractor}.
|
||||
* Query using a prepared statement, reading the {@link ResultSet} with a {@link AsyncResultSetExtractor}.
|
||||
*
|
||||
* @param preparedStatementCreator object that can create a {@link PreparedStatement} given a
|
||||
* {@link com.datastax.driver.core.Session}, must not be {@literal null}.
|
||||
* @param resultSetExtractor object that will extract results, must not be {@literal null}.
|
||||
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}
|
||||
* @return an arbitrary result object, as returned by the {@link AsyncResultSetExtractor}
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
<T> ListenableFuture<T> query(AsyncPreparedStatementCreator preparedStatementCreator,
|
||||
ResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
|
||||
AsyncResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query using a prepared statement, reading the {@link ResultSet} on a per-row basis with a
|
||||
@@ -684,7 +684,7 @@ public interface AsyncCqlOperations {
|
||||
|
||||
/**
|
||||
* Query using a prepared statement and a {@link PreparedStatementBinder} implementation that knows how to bind values
|
||||
* to the query, reading the {@link ResultSet} with a {@link ResultSetExtractor}.
|
||||
* to the query, reading the {@link ResultSet} with a {@link AsyncResultSetExtractor}.
|
||||
*
|
||||
* @param preparedStatementCreator object that can create a {@link PreparedStatement} given a
|
||||
* {@link com.datastax.driver.core.Session}, must not be {@literal null}.
|
||||
@@ -692,11 +692,11 @@ public interface AsyncCqlOperations {
|
||||
* be assumed to contain no bind parameters. Even if there are no bind parameters, this object may be used to
|
||||
* set fetch size and other performance options.
|
||||
* @param resultSetExtractor object that will extract results, must not be {@literal null}.
|
||||
* @return an arbitrary result object, as returned by the {@link ResultSetExtractor}.
|
||||
* @return an arbitrary result object, as returned by the {@link AsyncResultSetExtractor}.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
<T> ListenableFuture<T> query(AsyncPreparedStatementCreator preparedStatementCreator,
|
||||
@Nullable PreparedStatementBinder psb, ResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
|
||||
@Nullable PreparedStatementBinder psb, AsyncResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Query using a prepared statement and a {@link PreparedStatementBinder} implementation that knows how to bind values
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.cql;
|
||||
|
||||
import io.netty.util.concurrent.ImmediateExecutor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -26,21 +26,18 @@ import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.DataAccessUtils;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.cassandra.SessionFactory;
|
||||
import org.springframework.data.cassandra.core.cql.util.CassandraFutureAdapter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
import com.datastax.driver.core.BoundStatement;
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.ResultSetFuture;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.SimpleStatement;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.ResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
|
||||
/**
|
||||
* <b>This is the central class in the CQL core package for asynchronous Cassandra data access.</b> It simplifies the
|
||||
@@ -51,13 +48,13 @@ import com.google.common.util.concurrent.Futures;
|
||||
* <p>
|
||||
* Code using this class need only implement callback interfaces, giving them a clearly defined contract. The
|
||||
* {@link PreparedStatementCreator} callback interface creates a prepared statement given a Connection, providing CQL
|
||||
* and any necessary parameters. The {@link ResultSetExtractor} interface extracts values from a {@link ResultSet}. See
|
||||
* also {@link PreparedStatementBinder} and {@link RowMapper} for two popular alternative callback interfaces.
|
||||
* and any necessary parameters. The {@link AsyncResultSetExtractor} interface extracts values from a {@link ResultSet}.
|
||||
* See also {@link PreparedStatementBinder} and {@link RowMapper} for two popular alternative callback interfaces.
|
||||
* <p>
|
||||
* Can be used within a service implementation via direct instantiation with a {@link Session} reference, or get
|
||||
* prepared in an application context and given to services as bean reference. Note: The {@link Session} should always
|
||||
* be configured as a bean in the application context, in the first case given to the service directly, in the second
|
||||
* case to the prepared template.
|
||||
* Can be used within a service implementation via direct instantiation with a {@link CqlSession} reference, or get
|
||||
* prepared in an application context and given to services as bean reference. Note: The {@link CqlSession} should
|
||||
* always be configured as a bean in the application context, in the first case given to the service directly, in the
|
||||
* second case to the prepared template.
|
||||
* <p>
|
||||
* Because this class is parameterizable by the callback interfaces and the
|
||||
* {@link org.springframework.dao.support.PersistenceExceptionTranslator} interface, there should be no need to subclass
|
||||
@@ -74,7 +71,7 @@ import com.google.common.util.concurrent.Futures;
|
||||
* @see PreparedStatementCreator
|
||||
* @see PreparedStatementBinder
|
||||
* @see PreparedStatementCallback
|
||||
* @see ResultSetExtractor
|
||||
* @see AsyncResultSetExtractor
|
||||
* @see RowCallbackHandler
|
||||
* @see RowMapper
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator
|
||||
@@ -90,13 +87,12 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
public AsyncCqlTemplate() {}
|
||||
|
||||
/**
|
||||
* Create a new {@link AsyncCqlTemplate} with the given {@link Session}.
|
||||
* Create a new {@link AsyncCqlTemplate} with the given {@link CqlSession}.
|
||||
*
|
||||
* @param session the active Cassandra {@link Session}, must not be {@literal null}.
|
||||
* @throws IllegalStateException if {@link Session} is {@literal null}.
|
||||
* @see com.datastax.driver.core.Session
|
||||
* @param session the active Cassandra {@link CqlSession}, must not be {@literal null}.
|
||||
* @throws IllegalStateException if {@link CqlSession} is {@literal null}.
|
||||
*/
|
||||
public AsyncCqlTemplate(Session session) {
|
||||
public AsyncCqlTemplate(CqlSession session) {
|
||||
|
||||
Assert.notNull(session, "Session must not be null");
|
||||
|
||||
@@ -150,32 +146,30 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
|
||||
Assert.hasText(cql, "CQL must not be empty");
|
||||
|
||||
return new MappingListenableFutureAdapter<>(queryForResultSet(cql), ResultSet::wasApplied);
|
||||
return new MappingListenableFutureAdapter<>(queryForResultSet(cql), AsyncResultSet::wasApplied);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.AsyncResultSetExtractor)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<T> query(String cql, ResultSetExtractor<T> resultSetExtractor)
|
||||
public <T> ListenableFuture<T> query(String cql, AsyncResultSetExtractor<T> resultSetExtractor)
|
||||
throws DataAccessException {
|
||||
|
||||
Assert.hasText(cql, "CQL must not be empty");
|
||||
Assert.notNull(resultSetExtractor, "ResultSetExtractor must not be null");
|
||||
Assert.notNull(resultSetExtractor, "AsyncResultSetExtractor must not be null");
|
||||
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executing CQL Statement [{}]", cql);
|
||||
}
|
||||
|
||||
SimpleStatement simpleStatement = applyStatementSettings(new SimpleStatement(cql));
|
||||
CompletionStage<T> results = getCurrentSession().executeAsync(applyStatementSettings(newStatement(cql)))
|
||||
.thenApply(resultSetExtractor::extractData) //
|
||||
.thenCompose(ListenableFuture::completable);
|
||||
|
||||
ResultSetFuture results = getCurrentSession().executeAsync(simpleStatement);
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(
|
||||
new GuavaListenableFutureAdapter<>(results, ex -> translateExceptionIfPossible("Query", cql, ex)),
|
||||
resultSetExtractor::extractData), getExceptionTranslator());
|
||||
return new CassandraFutureAdapter<>(results, ex -> translateExceptionIfPossible("Query", cql, ex));
|
||||
} catch (DriverException e) {
|
||||
throw translateException("Query", cql, e);
|
||||
}
|
||||
@@ -188,10 +182,10 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
@Override
|
||||
public ListenableFuture<Void> query(String cql, RowCallbackHandler rowCallbackHandler) throws DataAccessException {
|
||||
|
||||
ListenableFuture<?> results = query(cql, newResultSetExtractor(rowCallbackHandler));
|
||||
ListenableFuture<?> results = query(cql, newAsyncResultSetExtractor(rowCallbackHandler));
|
||||
|
||||
return new MappingListenableFutureAdapter<>(results, o -> null);
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null),
|
||||
getExceptionTranslator());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -200,7 +194,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<List<T>> query(String cql, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return query(cql, newResultSetExtractor(rowMapper));
|
||||
return query(cql, newAsyncResultSetExtractor(rowMapper));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -209,7 +203,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<List<Map<String, Object>>> queryForList(String cql) throws DataAccessException {
|
||||
return query(cql, newResultSetExtractor(newColumnMapRowMapper()));
|
||||
return query(cql, newAsyncResultSetExtractor(newColumnMapRowMapper()));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -218,7 +212,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<List<T>> queryForList(String cql, Class<T> elementType) throws DataAccessException {
|
||||
return query(cql, newResultSetExtractor(newSingleColumnRowMapper(elementType)));
|
||||
return query(cql, newAsyncResultSetExtractor(newSingleColumnRowMapper(elementType)));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -246,7 +240,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
@Override
|
||||
public <T> ListenableFuture<T> queryForObject(String cql, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
|
||||
ListenableFuture<List<T>> results = query(cql, newResultSetExtractor(rowMapper));
|
||||
ListenableFuture<List<T>> results = query(cql, newAsyncResultSetExtractor(rowMapper));
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(
|
||||
new MappingListenableFutureAdapter<>(results, DataAccessUtils::requiredSingleResult), getExceptionTranslator());
|
||||
@@ -257,50 +251,49 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForResultSet(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<ResultSet> queryForResultSet(String cql) throws DataAccessException {
|
||||
return query(cql, rs -> rs);
|
||||
public ListenableFuture<AsyncResultSet> queryForResultSet(String cql) throws DataAccessException {
|
||||
return query(cql, AsyncCqlTemplate::toResultSet);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.Statement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.Statement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#execute(com.datastax.driver.core.Statement)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#execute(com.datastax.oss.driver.api.core.cql.Statement)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<Boolean> execute(Statement statement) throws DataAccessException {
|
||||
public ListenableFuture<Boolean> execute(Statement<?> statement) throws DataAccessException {
|
||||
|
||||
Assert.notNull(statement, "CQL Statement must not be null");
|
||||
|
||||
return new MappingListenableFutureAdapter<>(queryForResultSet(statement), ResultSet::wasApplied);
|
||||
return new MappingListenableFutureAdapter<>(queryForResultSet(statement), AsyncResultSet::wasApplied);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(com.datastax.driver.core.Statement, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(com.datastax.oss.driver.api.core.cql.Statement, org.springframework.data.cassandra.core.cql.AsyncResultSetExtractor)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<T> query(Statement statement, ResultSetExtractor<T> resultSetExtractor)
|
||||
public <T> ListenableFuture<T> query(Statement<?> statement, AsyncResultSetExtractor<T> resultSetExtractor)
|
||||
throws DataAccessException {
|
||||
|
||||
Assert.notNull(statement, "CQL Statement must not be null");
|
||||
Assert.notNull(resultSetExtractor, "ResultSetExtractor must not be null");
|
||||
Assert.notNull(resultSetExtractor, "AsyncResultSetExtractor must not be null");
|
||||
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executing CQL Statement [{}]", statement);
|
||||
}
|
||||
|
||||
ResultSetFuture results = getCurrentSession().executeAsync(applyStatementSettings(statement));
|
||||
CompletionStage<T> results = getCurrentSession() //
|
||||
.executeAsync(applyStatementSettings(statement)) //
|
||||
.thenApply(resultSetExtractor::extractData) //
|
||||
.thenCompose(ListenableFuture::completable);
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(
|
||||
new MappingListenableFutureAdapter<>(
|
||||
new GuavaListenableFutureAdapter<>(results,
|
||||
ex -> translateExceptionIfPossible("Query", statement.toString(), ex)),
|
||||
resultSetExtractor::extractData),
|
||||
getExceptionTranslator());
|
||||
return new CassandraFutureAdapter<>(results,
|
||||
ex -> translateExceptionIfPossible("Query", statement.toString(), ex));
|
||||
} catch (DriverException e) {
|
||||
throw translateException("Query", statement.toString(), e);
|
||||
}
|
||||
@@ -308,13 +301,13 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(com.datastax.driver.core.Statement, org.springframework.data.cassandra.core.cql.RowCallbackHandler)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(com.datastax.oss.driver.api.core.cql.Statement, org.springframework.data.cassandra.core.cql.RowCallbackHandler)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<Void> query(Statement statement, RowCallbackHandler rowCallbackHandler)
|
||||
public ListenableFuture<Void> query(Statement<?> statement, RowCallbackHandler rowCallbackHandler)
|
||||
throws DataAccessException {
|
||||
|
||||
ListenableFuture<?> result = query(statement, newResultSetExtractor(rowCallbackHandler));
|
||||
ListenableFuture<?> result = query(statement, newAsyncResultSetExtractor(rowCallbackHandler));
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(result, o -> null),
|
||||
getExceptionTranslator());
|
||||
@@ -322,59 +315,61 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(com.datastax.driver.core.Statement, org.springframework.data.cassandra.core.cql.RowMapper)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(com.datastax.oss.driver.api.core.cql.Statement, org.springframework.data.cassandra.core.cql.RowMapper)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<List<T>> query(Statement statement, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return query(statement, newResultSetExtractor(rowMapper));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForList(com.datastax.driver.core.Statement)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<List<Map<String, Object>>> queryForList(Statement statement) throws DataAccessException {
|
||||
return query(statement, newResultSetExtractor(newColumnMapRowMapper()));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForList(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<List<T>> queryForList(Statement statement, Class<T> elementType)
|
||||
public <T> ListenableFuture<List<T>> query(Statement<?> statement, RowMapper<T> rowMapper)
|
||||
throws DataAccessException {
|
||||
return query(statement, newResultSetExtractor(newSingleColumnRowMapper(elementType)));
|
||||
return query(statement, newAsyncResultSetExtractor(rowMapper));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForMap(com.datastax.driver.core.Statement)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForList(com.datastax.oss.driver.api.core.cql.Statement)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<Map<String, Object>> queryForMap(Statement statement) throws DataAccessException {
|
||||
public ListenableFuture<List<Map<String, Object>>> queryForList(Statement<?> statement) throws DataAccessException {
|
||||
return query(statement, newAsyncResultSetExtractor(newColumnMapRowMapper()));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForList(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<List<T>> queryForList(Statement<?> statement, Class<T> elementType)
|
||||
throws DataAccessException {
|
||||
return query(statement, newAsyncResultSetExtractor(newSingleColumnRowMapper(elementType)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForMap(com.datastax.oss.driver.api.core.cql.Statement)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<Map<String, Object>> queryForMap(Statement<?> statement) throws DataAccessException {
|
||||
return queryForObject(statement, newColumnMapRowMapper());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForObject(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForObject(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<T> queryForObject(Statement statement, Class<T> requiredType) throws DataAccessException {
|
||||
public <T> ListenableFuture<T> queryForObject(Statement<?> statement, Class<T> requiredType)
|
||||
throws DataAccessException {
|
||||
return queryForObject(statement, newSingleColumnRowMapper(requiredType));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForObject(com.datastax.driver.core.Statement, org.springframework.data.cassandra.core.cql.RowMapper)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForObject(com.datastax.oss.driver.api.core.cql.Statement, org.springframework.data.cassandra.core.cql.RowMapper)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<T> queryForObject(Statement statement, RowMapper<T> rowMapper)
|
||||
public <T> ListenableFuture<T> queryForObject(Statement<?> statement, RowMapper<T> rowMapper)
|
||||
throws DataAccessException {
|
||||
|
||||
ListenableFuture<List<T>> results = query(statement, newResultSetExtractor(rowMapper));
|
||||
ListenableFuture<List<T>> results = query(statement, newAsyncResultSetExtractor(rowMapper));
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(
|
||||
new MappingListenableFutureAdapter<>(results, DataAccessUtils::requiredSingleResult), getExceptionTranslator());
|
||||
@@ -382,11 +377,11 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForResultSet(com.datastax.driver.core.Statement)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForResultSet(com.datastax.oss.driver.api.core.cql.Statement)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<ResultSet> queryForResultSet(Statement statement) throws DataAccessException {
|
||||
return query(statement, rs -> rs);
|
||||
public ListenableFuture<AsyncResultSet> queryForResultSet(Statement<?> statement) throws DataAccessException {
|
||||
return query(statement, AsyncCqlTemplate::toResultSet);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -401,7 +396,8 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
public ListenableFuture<Boolean> execute(AsyncPreparedStatementCreator preparedStatementCreator)
|
||||
throws DataAccessException {
|
||||
|
||||
return query(preparedStatementCreator, ResultSet::wasApplied);
|
||||
return new MappingListenableFutureAdapter<>(query(preparedStatementCreator, AsyncCqlTemplate::toResultSet),
|
||||
AsyncResultSet::wasApplied);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -421,7 +417,8 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
public ListenableFuture<Boolean> execute(String cql, @Nullable PreparedStatementBinder psb)
|
||||
throws DataAccessException {
|
||||
|
||||
return query(newAsyncPreparedStatementCreator(cql), psb, ResultSet::wasApplied);
|
||||
return new MappingListenableFutureAdapter<>(
|
||||
query(newAsyncPreparedStatementCreator(cql), psb, AsyncCqlTemplate::toResultSet), AsyncResultSet::wasApplied);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -451,11 +448,11 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
logger.debug("Preparing statement [{}] using {}", toCql(preparedStatementCreator), preparedStatementCreator);
|
||||
}
|
||||
|
||||
Session currentSession = getCurrentSession();
|
||||
CqlSession currentSession = getCurrentSession();
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(
|
||||
preparedStatementCreator.createPreparedStatement(currentSession), preparedStatement -> {
|
||||
try {
|
||||
return action.doInPreparedStatement(currentSession, applyStatementSettings(preparedStatement));
|
||||
return action.doInPreparedStatement(currentSession, preparedStatement);
|
||||
} catch (DriverException e) {
|
||||
throw translateException(exceptionTranslator, e);
|
||||
}
|
||||
@@ -468,11 +465,11 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(org.springframework.data.cassandra.core.cql.AsyncPreparedStatementCreator, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(org.springframework.data.cassandra.core.cql.AsyncPreparedStatementCreator, org.springframework.data.cassandra.core.cql.AsyncResultSetExtractor)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<T> query(AsyncPreparedStatementCreator preparedStatementCreator,
|
||||
ResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
|
||||
AsyncResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
|
||||
|
||||
return query(preparedStatementCreator, null, resultSetExtractor);
|
||||
}
|
||||
@@ -485,7 +482,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
public ListenableFuture<Void> query(AsyncPreparedStatementCreator preparedStatementCreator,
|
||||
RowCallbackHandler rowCallbackHandler) throws DataAccessException {
|
||||
|
||||
ListenableFuture<?> results = query(preparedStatementCreator, null, newResultSetExtractor(rowCallbackHandler));
|
||||
ListenableFuture<?> results = query(preparedStatementCreator, null, newAsyncResultSetExtractor(rowCallbackHandler));
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null),
|
||||
getExceptionTranslator());
|
||||
@@ -499,19 +496,19 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
public <T> ListenableFuture<List<T>> query(AsyncPreparedStatementCreator preparedStatementCreator,
|
||||
RowMapper<T> rowMapper) throws DataAccessException {
|
||||
|
||||
return query(preparedStatementCreator, null, newResultSetExtractor(rowMapper));
|
||||
return query(preparedStatementCreator, null, newAsyncResultSetExtractor(rowMapper));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(org.springframework.data.cassandra.core.cql.AsyncPreparedStatementCreator, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(org.springframework.data.cassandra.core.cql.AsyncPreparedStatementCreator, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.AsyncResultSetExtractor)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<T> query(AsyncPreparedStatementCreator preparedStatementCreator,
|
||||
@Nullable PreparedStatementBinder psb, ResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
|
||||
@Nullable PreparedStatementBinder psb, AsyncResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
|
||||
|
||||
Assert.notNull(preparedStatementCreator, "AsyncPreparedStatementCreator must not be null");
|
||||
Assert.notNull(resultSetExtractor, "ResultSetExtractor object must not be null");
|
||||
Assert.notNull(resultSetExtractor, "AsyncResultSetExtractor object must not be null");
|
||||
|
||||
PersistenceExceptionTranslator exceptionTranslator = ex -> translateExceptionIfPossible("Query",
|
||||
toCql(preparedStatementCreator), ex);
|
||||
@@ -522,9 +519,9 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
logger.debug("Preparing statement [{}] using {}", toCql(preparedStatementCreator), preparedStatementCreator);
|
||||
}
|
||||
|
||||
Session session = getCurrentSession();
|
||||
CqlSession session = getCurrentSession();
|
||||
|
||||
ListenableFuture<BoundStatement> statementFuture = new MappingListenableFutureAdapter<>(
|
||||
ListenableFuture<Statement<?>> statementFuture = new MappingListenableFutureAdapter<>(
|
||||
preparedStatementCreator.createPreparedStatement(session), preparedStatement -> {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executing prepared statement [{}]", preparedStatement);
|
||||
@@ -533,37 +530,12 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
return applyStatementSettings(psb != null ? psb.bindValues(preparedStatement) : preparedStatement.bind());
|
||||
});
|
||||
|
||||
SettableListenableFuture<T> settableListenableFuture = new SettableListenableFuture<>();
|
||||
|
||||
statementFuture.addCallback(
|
||||
boundStatement -> Futures.addCallback(session.executeAsync(boundStatement), new FutureCallback<ResultSet>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable ResultSet result) {
|
||||
try {
|
||||
settableListenableFuture.set(result != null ? resultSetExtractor.extractData(result) : null);
|
||||
} catch (DriverException e) {
|
||||
settableListenableFuture.setException(translateException(exceptionTranslator, e));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
if (ex instanceof DriverException) {
|
||||
settableListenableFuture.setException(translateException(exceptionTranslator, (DriverException) ex));
|
||||
} else {
|
||||
settableListenableFuture.setException(ex);
|
||||
}
|
||||
}
|
||||
}, ImmediateExecutor.INSTANCE), ex -> {
|
||||
if (ex instanceof DriverException) {
|
||||
settableListenableFuture.setException(translateException(exceptionTranslator, (DriverException) ex));
|
||||
} else {
|
||||
settableListenableFuture.setException(ex);
|
||||
}
|
||||
});
|
||||
|
||||
return settableListenableFuture;
|
||||
CompletableFuture<T> result = statementFuture.completable() //
|
||||
.thenCompose(session::executeAsync) //
|
||||
.thenApply(resultSetExtractor::extractData) //
|
||||
.thenCompose(ListenableFuture::completable);
|
||||
|
||||
return new CassandraFutureAdapter<>(result, exceptionTranslator);
|
||||
} catch (DriverException e) {
|
||||
throw translateException(exceptionTranslator, e);
|
||||
}
|
||||
@@ -577,7 +549,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
public ListenableFuture<Void> query(AsyncPreparedStatementCreator preparedStatementCreator,
|
||||
@Nullable PreparedStatementBinder psb, RowCallbackHandler rowCallbackHandler) throws DataAccessException {
|
||||
|
||||
ListenableFuture<?> results = query(preparedStatementCreator, psb, newResultSetExtractor(rowCallbackHandler));
|
||||
ListenableFuture<?> results = query(preparedStatementCreator, psb, newAsyncResultSetExtractor(rowCallbackHandler));
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null),
|
||||
getExceptionTranslator());
|
||||
@@ -590,15 +562,15 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
@Override
|
||||
public <T> ListenableFuture<List<T>> query(AsyncPreparedStatementCreator preparedStatementCreator,
|
||||
@Nullable PreparedStatementBinder psb, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return query(preparedStatementCreator, psb, newResultSetExtractor(rowMapper));
|
||||
return query(preparedStatementCreator, psb, newAsyncResultSetExtractor(rowMapper));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.ResultSetExtractor, java.lang.Object[])
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.AsyncResultSetExtractor, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<T> query(String cql, ResultSetExtractor<T> resultSetExtractor, Object... args)
|
||||
public <T> ListenableFuture<T> query(String cql, AsyncResultSetExtractor<T> resultSetExtractor, Object... args)
|
||||
throws DataAccessException {
|
||||
return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args), resultSetExtractor);
|
||||
}
|
||||
@@ -612,7 +584,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
throws DataAccessException {
|
||||
|
||||
ListenableFuture<?> results = query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args),
|
||||
newResultSetExtractor(rowCallbackHandler));
|
||||
newAsyncResultSetExtractor(rowCallbackHandler));
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null),
|
||||
getExceptionTranslator());
|
||||
@@ -626,16 +598,16 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
public <T> ListenableFuture<List<T>> query(String cql, RowMapper<T> rowMapper, Object... args)
|
||||
throws DataAccessException {
|
||||
return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args),
|
||||
newResultSetExtractor(rowMapper));
|
||||
newAsyncResultSetExtractor(rowMapper));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#query(java.lang.String, org.springframework.data.cassandra.core.cql.PreparedStatementBinder, org.springframework.data.cassandra.core.cql.AsyncResultSetExtractor)
|
||||
*/
|
||||
@Override
|
||||
public <T> ListenableFuture<T> query(String cql, @Nullable PreparedStatementBinder psb,
|
||||
ResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
|
||||
AsyncResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
|
||||
|
||||
return query(newAsyncPreparedStatementCreator(cql), psb, resultSetExtractor);
|
||||
}
|
||||
@@ -649,7 +621,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
RowCallbackHandler rowCallbackHandler) throws DataAccessException {
|
||||
|
||||
ListenableFuture<?> results = query(newAsyncPreparedStatementCreator(cql), psb,
|
||||
newResultSetExtractor(rowCallbackHandler));
|
||||
newAsyncResultSetExtractor(rowCallbackHandler));
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(new MappingListenableFutureAdapter<>(results, o -> null),
|
||||
getExceptionTranslator());
|
||||
@@ -663,7 +635,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
public <T> ListenableFuture<List<T>> query(String cql, @Nullable PreparedStatementBinder psb, RowMapper<T> rowMapper)
|
||||
throws DataAccessException {
|
||||
|
||||
return query(newAsyncPreparedStatementCreator(cql), psb, newResultSetExtractor(rowMapper));
|
||||
return query(newAsyncPreparedStatementCreator(cql), psb, newAsyncResultSetExtractor(rowMapper));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -675,7 +647,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
throws DataAccessException {
|
||||
|
||||
return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args),
|
||||
newResultSetExtractor(newColumnMapRowMapper()));
|
||||
newAsyncResultSetExtractor(newColumnMapRowMapper()));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -687,7 +659,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
throws DataAccessException {
|
||||
|
||||
return query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args),
|
||||
newResultSetExtractor(newSingleColumnRowMapper(elementType)));
|
||||
newAsyncResultSetExtractor(newSingleColumnRowMapper(elementType)));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -719,7 +691,7 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
throws DataAccessException {
|
||||
|
||||
ListenableFuture<List<T>> results = query(newAsyncPreparedStatementCreator(cql), newPreparedStatementBinder(args),
|
||||
newResultSetExtractor(rowMapper, 1));
|
||||
newAsyncResultSetExtractor(rowMapper));
|
||||
|
||||
return new ExceptionTranslatingListenableFutureAdapter<>(
|
||||
new MappingListenableFutureAdapter<>(results, DataAccessUtils::requiredSingleResult), getExceptionTranslator());
|
||||
@@ -730,26 +702,14 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
* @see org.springframework.data.cassandra.core.cql.AsyncCqlOperations#queryForResultSet(java.lang.String, java.lang.Object[])
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<ResultSet> queryForResultSet(String cql, Object... args) throws DataAccessException {
|
||||
return query(cql, rs -> rs, args);
|
||||
public ListenableFuture<AsyncResultSet> queryForResultSet(String cql, Object... args) throws DataAccessException {
|
||||
return query(cql, AsyncCqlTemplate::toResultSet, args);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Implementation hooks and helper methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a new CQL-based {@link AsyncPreparedStatementCreator} using the CQL passed in. By default, we'll create an
|
||||
* {@link SimpleAsyncPreparedStatementCreator}. This method allows for the creation to be overridden by subclasses.
|
||||
*
|
||||
* @param cql static CQL to execute, must not be empty or {@literal null}.
|
||||
* @return the new {@link AsyncPreparedStatementCreator} to use
|
||||
*/
|
||||
protected AsyncPreparedStatementCreator newAsyncPreparedStatementCreator(String cql) {
|
||||
return new SimpleAsyncPreparedStatementCreator(cql,
|
||||
ex -> translateExceptionIfPossible("PrepareStatement", cql, ex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the given {@link DriverException} into a generic {@link DataAccessException}.
|
||||
*
|
||||
@@ -774,10 +734,51 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
*/
|
||||
@Nullable
|
||||
protected DataAccessException translateExceptionIfPossible(String task, @Nullable String cql, RuntimeException ex) {
|
||||
return (ex instanceof DriverException ? translate(task, cql, (DriverException) ex) : null);
|
||||
return translate(task, cql, ex);
|
||||
}
|
||||
|
||||
private Session getCurrentSession() {
|
||||
/**
|
||||
* Create a new CQL-based {@link AsyncPreparedStatementCreator} using the CQL passed in. By default, we'll create an
|
||||
* {@link SimpleAsyncPreparedStatementCreator}. This method allows for the creation to be overridden by subclasses.
|
||||
*
|
||||
* @param cql static CQL to execute, must not be empty or {@literal null}.
|
||||
* @return the new {@link AsyncPreparedStatementCreator} to use
|
||||
*/
|
||||
protected AsyncPreparedStatementCreator newAsyncPreparedStatementCreator(String cql) {
|
||||
return new SimpleAsyncPreparedStatementCreator(cql,
|
||||
ex -> translateExceptionIfPossible("PrepareStatement", cql, ex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the {@link ResultSetExtractor} initialized with and adapting the given
|
||||
* {@link RowCallbackHandler}.
|
||||
*
|
||||
* @param rowCallbackHandler {@link RowCallbackHandler} to adapt as a {@link ResultSetExtractor}.
|
||||
* @return a {@link ResultSetExtractor} implementation adapting an instance of the {@link RowCallbackHandler}.
|
||||
* @see AsyncRowCallbackHandlerResultSetExtractor
|
||||
* @see ResultSetExtractor
|
||||
* @see RowCallbackHandler
|
||||
*/
|
||||
protected AsyncRowCallbackHandlerResultSetExtractor newAsyncResultSetExtractor(
|
||||
RowCallbackHandler rowCallbackHandler) {
|
||||
return new AsyncRowCallbackHandlerResultSetExtractor(rowCallbackHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the {@link ResultSetExtractor} initialized with and adapting the given
|
||||
* {@link RowMapper}.
|
||||
*
|
||||
* @param rowMapper {@link RowMapper} to adapt as a {@link ResultSetExtractor}.
|
||||
* @return a {@link ResultSetExtractor} implementation adapting an instance of the {@link RowMapper}.
|
||||
* @see ResultSetExtractor
|
||||
* @see RowMapper
|
||||
* @see RowMapperResultSetExtractor
|
||||
*/
|
||||
protected <T> AsyncRowMapperResultSetExtractor<T> newAsyncResultSetExtractor(RowMapper<T> rowMapper) {
|
||||
return new AsyncRowMapperResultSetExtractor<>(rowMapper);
|
||||
}
|
||||
|
||||
private CqlSession getCurrentSession() {
|
||||
|
||||
SessionFactory sessionFactory = getSessionFactory();
|
||||
|
||||
@@ -786,6 +787,14 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
return sessionFactory.getSession();
|
||||
}
|
||||
|
||||
private static ListenableFuture<AsyncResultSet> toResultSet(AsyncResultSet resultSet) {
|
||||
|
||||
SettableListenableFuture<AsyncResultSet> future = new SettableListenableFuture<>();
|
||||
future.set(resultSet);
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
private static RuntimeException translateException(PersistenceExceptionTranslator exceptionTranslator,
|
||||
DriverException e) {
|
||||
|
||||
@@ -795,17 +804,16 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
|
||||
private static class SimpleAsyncPreparedStatementCreator implements AsyncPreparedStatementCreator, CqlProvider {
|
||||
|
||||
private final PersistenceExceptionTranslator persistenceExceptionTranslator;
|
||||
private final PersistenceExceptionTranslator exceptionTranslator;
|
||||
|
||||
private final String cql;
|
||||
|
||||
private SimpleAsyncPreparedStatementCreator(String cql,
|
||||
PersistenceExceptionTranslator persistenceExceptionTranslator) {
|
||||
private SimpleAsyncPreparedStatementCreator(String cql, PersistenceExceptionTranslator exceptionTranslator) {
|
||||
|
||||
Assert.hasText(cql, "CQL must not be empty");
|
||||
|
||||
this.cql = cql;
|
||||
this.persistenceExceptionTranslator = persistenceExceptionTranslator;
|
||||
this.exceptionTranslator = exceptionTranslator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -814,9 +822,30 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<PreparedStatement> createPreparedStatement(Session session) throws DriverException {
|
||||
public ListenableFuture<PreparedStatement> createPreparedStatement(CqlSession session) throws DriverException {
|
||||
return new CassandraFutureAdapter<>(session.prepareAsync(getCql()),
|
||||
exceptionTranslator::translateExceptionIfPossible);
|
||||
}
|
||||
}
|
||||
|
||||
return new GuavaListenableFutureAdapter<>(session.prepareAsync(getCql()), this.persistenceExceptionTranslator);
|
||||
/**
|
||||
* Adapter to enable use of a {@link RowCallbackHandler} inside a {@link ResultSetExtractor}.
|
||||
*/
|
||||
protected static class AsyncRowCallbackHandlerResultSetExtractor implements AsyncResultSetExtractor<Void> {
|
||||
|
||||
private final RowCallbackHandler rowCallbackHandler;
|
||||
|
||||
protected AsyncRowCallbackHandlerResultSetExtractor(RowCallbackHandler rowCallbackHandler) {
|
||||
this.rowCallbackHandler = rowCallbackHandler;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.ResultSetExtractor#extractData(com.datastax.driver.core.ResultSet)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public ListenableFuture<Void> extractData(AsyncResultSet resultSet) {
|
||||
return AsyncResultStream.from(resultSet).forEach(rowCallbackHandler::processRow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,4 +864,5 @@ public class AsyncCqlTemplate extends CassandraAccessor implements AsyncCqlOpera
|
||||
return mapper.apply(adapteeResult);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ package org.springframework.data.cassandra.core.cql;
|
||||
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
|
||||
|
||||
/**
|
||||
* One of the two central callback interfaces used by the {@link AsyncCqlTemplate} class. This interface prepares a CQL
|
||||
* statement returning a {@link org.springframework.util.concurrent.ListenableFuture} given a {@link Session}, provided
|
||||
* by the {@link CqlTemplate} class.
|
||||
* statement returning a {@link org.springframework.util.concurrent.ListenableFuture} given a {@link CqlSession},
|
||||
* provided by the {@link CqlTemplate} class.
|
||||
* <p>
|
||||
* Implementations may either create new prepared statements or reuse cached instances. Implementations do not need to
|
||||
* concern themselves with {@link DriverException}s that may be thrown from operations they attempt. The
|
||||
@@ -51,5 +51,5 @@ public interface AsyncPreparedStatementCreator {
|
||||
* @throws DriverException there is no need to catch DriverException that may be thrown in the implementation of this
|
||||
* method. The {@link AsyncCqlTemplate} class will handle them.
|
||||
*/
|
||||
ListenableFuture<PreparedStatement> createPreparedStatement(Session session) throws DriverException;
|
||||
ListenableFuture<PreparedStatement> createPreparedStatement(CqlSession session) throws DriverException;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.cql;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
|
||||
|
||||
/**
|
||||
* Callback interface used by {@link AsyncCqlTemplate}'s query methods. Implementations of this interface perform the
|
||||
* actual work of extracting results from a {@link AsyncResultSet}, but don't need to worry about exception handling.
|
||||
* {@link DriverException}s will be caught and handled by the calling {@link AsyncCqlTemplate}.
|
||||
* <p>
|
||||
* This interface is mainly used within the CQL framework itself. A {@link RowMapper} is usually a simpler choice for
|
||||
* {@link AsyncResultSet} processing, mapping one result object per row instead of one result object for the entire
|
||||
* {@link AsyncResultSet}.
|
||||
* <p>
|
||||
* Note: In contrast to a {@link RowCallbackHandler}, a {@link AsyncResultSetExtractor} object is typically stateless
|
||||
* and thus reusable, as long as it doesn't access stateful resources or keep result state within the object.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
* @see AsyncCqlTemplate
|
||||
* @see RowMapper
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface AsyncResultSetExtractor<T> {
|
||||
|
||||
/**
|
||||
* Implementations must implement this method to process the entire {@link AsyncResultSet}.
|
||||
*
|
||||
* @param resultSet {@link AsyncResultSet} to extract data from.
|
||||
* @return an arbitrary result object, or {@literal null} if none (the extractor will typically be stateful in the
|
||||
* latter case).
|
||||
* @throws DriverException if a {@link DriverException} is encountered getting column values or navigating (that is,
|
||||
* there's no need to catch {@link DriverException})
|
||||
* @throws DataAccessException in case of custom exceptions
|
||||
*/
|
||||
@Nullable
|
||||
ListenableFuture<T> extractData(AsyncResultSet resultSet) throws DriverException, DataAccessException;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.cql;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
|
||||
|
||||
/**
|
||||
* Adapter implementation of the {@link ResultSetExtractor} interface that delegates to a {@link RowMapper} which is
|
||||
* supposed to create an object for each row. Each object is added to the results List of this
|
||||
* {@link ResultSetExtractor}.
|
||||
* <p>
|
||||
* Useful for the typical case of one object per row in the database table. The number of entries in the results will
|
||||
* match the number of rows.
|
||||
* <p>
|
||||
* Note that a {@link RowMapper} object is typically stateless and thus reusable.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.0
|
||||
* @see RowMapper
|
||||
* @see AsyncCqlTemplate
|
||||
*/
|
||||
public class AsyncRowMapperResultSetExtractor<T> implements AsyncResultSetExtractor<List<T>> {
|
||||
|
||||
private final RowMapper<T> rowMapper;
|
||||
|
||||
/**
|
||||
* Create a new {@link AsyncRowMapperResultSetExtractor}.
|
||||
*
|
||||
* @param rowMapper the {@link RowMapper} which creates an object for each row, must not be {@literal null}.
|
||||
*/
|
||||
public AsyncRowMapperResultSetExtractor(RowMapper<T> rowMapper) {
|
||||
|
||||
Assert.notNull(rowMapper, "RowMapper is must not be null");
|
||||
|
||||
this.rowMapper = rowMapper;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.ResultSetExtractor#extractData(com.datastax.driver.core.ResultSet)
|
||||
*/
|
||||
@Override
|
||||
public ListenableFuture<List<T>> extractData(AsyncResultSet resultSet) throws DriverException, DataAccessException {
|
||||
return AsyncResultStream.from(resultSet).map(rowMapper).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -18,16 +18,16 @@ package org.springframework.data.cassandra.core.cql;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
|
||||
/**
|
||||
* Generic callback interface for code that operates asynchronously on a Cassandra {@link Session}. Allows to execute
|
||||
* Generic callback interface for code that operates asynchronously on a Cassandra {@link CqlSession}. Allows to execute
|
||||
* any number of operations on a single session, using any type and number of statements.
|
||||
* <p>
|
||||
* This is particularly useful for delegating to existing data access code that expects a {@link Session} to work on and
|
||||
* throws {@link DriverException}. For newly written code, it is strongly recommended to use {@link CqlTemplate}'s more
|
||||
* specific operations, for example a {@code query} or {@code update} variant.
|
||||
* This is particularly useful for delegating to existing data access code that expects a {@link CqlSession} to work on
|
||||
* and throws {@link DriverException}. For newly written code, it is strongly recommended to use {@link CqlTemplate}'s
|
||||
* more specific operations, for example a {@code query} or {@code update} variant.
|
||||
*
|
||||
* @author David Webb
|
||||
* @author Mark Paluch
|
||||
@@ -39,8 +39,8 @@ import com.datastax.driver.core.exceptions.DriverException;
|
||||
public interface AsyncSessionCallback<T> {
|
||||
|
||||
/**
|
||||
* Gets called by {@link CqlTemplate#execute} with an active Cassandra {@link Session}. Does not need to care about
|
||||
* activating or closing the {@link Session}.
|
||||
* Gets called by {@link CqlTemplate#execute} with an active Cassandra {@link CqlSession}. Does not need to care about
|
||||
* activating or closing the {@link CqlSession}.
|
||||
* <p>
|
||||
* Allows for returning a result object created within the callback, i.e. a domain object or a collection of domain
|
||||
* objects. Note that there's special support for single step actions: see {@link CqlTemplate#queryForObject} etc. A
|
||||
@@ -54,5 +54,5 @@ public interface AsyncSessionCallback<T> {
|
||||
* @see AsyncCqlTemplate#queryForObject(String, Class)
|
||||
* @see AsyncCqlTemplate#queryForResultSet(String)
|
||||
*/
|
||||
ListenableFuture<T> doInSession(Session session) throws DriverException, DataAccessException;
|
||||
ListenableFuture<T> doInSession(CqlSession session) throws DriverException, DataAccessException;
|
||||
}
|
||||
|
||||
@@ -20,11 +20,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
|
||||
|
||||
/**
|
||||
* This {@link PreparedStatementCreator} maintains a static cache of all prepared statements for the duration of the JVM
|
||||
@@ -43,7 +45,7 @@ import com.datastax.driver.core.exceptions.DriverException;
|
||||
@Deprecated
|
||||
public class CachedPreparedStatementCreator implements PreparedStatementCreator {
|
||||
|
||||
private static final Map<Session, Map<String, PreparedStatement>> CACHE = new ConcurrentHashMap<>();
|
||||
private static final Map<CqlSession, Map<String, PreparedStatement>> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@@ -74,11 +76,12 @@ public class CachedPreparedStatementCreator implements PreparedStatementCreator
|
||||
* @see org.springframework.data.cassandra.core.cql.PreparedStatementCreator#createPreparedStatement(com.datastax.driver.core.Session)
|
||||
*/
|
||||
@Override
|
||||
public PreparedStatement createPreparedStatement(Session session) throws DriverException {
|
||||
public PreparedStatement createPreparedStatement(CqlSession session) throws DriverException {
|
||||
|
||||
String cacheKey = String.valueOf(session.getLoggedKeyspace()).concat("|").concat(this.cql);
|
||||
CqlIdentifier keyspace = session.getKeyspace().orElse(CqlIdentifier.fromCql("unknown"));
|
||||
String cacheKey = keyspace.asInternal().concat("|").concat(this.cql);
|
||||
|
||||
log.debug("Cacheable PreparedStatement in Keyspace {}", session.getLoggedKeyspace());
|
||||
log.debug("Cacheable PreparedStatement in Keyspace {}", keyspace.asCql(true));
|
||||
|
||||
Map<String, PreparedStatement> sessionCache = getOrCreateSessionLocalCache(session);
|
||||
|
||||
@@ -86,7 +89,7 @@ public class CachedPreparedStatementCreator implements PreparedStatementCreator
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Map<String, PreparedStatement> getOrCreateSessionLocalCache(Session session) {
|
||||
private Map<String, PreparedStatement> getOrCreateSessionLocalCache(CqlSession session) {
|
||||
|
||||
Map<String, PreparedStatement> sessionMap = CACHE.get(session);
|
||||
|
||||
@@ -107,7 +110,7 @@ public class CachedPreparedStatementCreator implements PreparedStatementCreator
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private PreparedStatement getOrPrepareStatement(Session session, String cacheKey,
|
||||
private PreparedStatement getOrPrepareStatement(CqlSession session, String cacheKey,
|
||||
Map<String, PreparedStatement> sessionCache) {
|
||||
|
||||
PreparedStatement preparedStatement = sessionCache.get(cacheKey);
|
||||
|
||||
@@ -17,10 +17,10 @@ package org.springframework.data.cassandra.core.cql;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.cassandra.SessionFactory;
|
||||
@@ -28,21 +28,18 @@ import org.springframework.data.cassandra.core.cql.session.DefaultSessionFactory
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.ConsistencyLevel;
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.driver.core.policies.RetryPolicy;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.oss.driver.api.core.ConsistencyLevel;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
import com.datastax.oss.driver.api.core.retry.RetryPolicy;
|
||||
|
||||
/**
|
||||
* {@link CassandraAccessor} provides access to a Cassandra {@link SessionFactory} and the
|
||||
* {@link CassandraExceptionTranslator}.
|
||||
* <p>
|
||||
* Classes providing a higher abstraction level usually extend {@link CassandraAccessor} to provide a richer set of
|
||||
* functionality on top of a {@link SessionFactory} using {@link Session}.
|
||||
* functionality on top of a {@link SessionFactory} using {@link CqlSession}.
|
||||
*
|
||||
* @author David Webb
|
||||
* @author Mark Paluch
|
||||
@@ -52,38 +49,33 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
*/
|
||||
public class CassandraAccessor implements InitializingBean {
|
||||
|
||||
/**
|
||||
* Placeholder for default values.
|
||||
*/
|
||||
private static final Statement DEFAULTS = QueryBuilder.select().from("DEFAULT");
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private CqlExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
|
||||
|
||||
/**
|
||||
* If this variable is set to a non-negative value, it will be used for setting the {@code fetchSize} property on
|
||||
* If this variable is set to a non-negative value, it will be used for setting the {@code pageSize} property on
|
||||
* statements used for query processing.
|
||||
*/
|
||||
private int fetchSize = -1;
|
||||
private int pageSize = -1;
|
||||
|
||||
/**
|
||||
* If this variable is set to a value, it will be used for setting the {@code consistencyLevel} property on statements
|
||||
* used for query processing.
|
||||
*/
|
||||
private @Nullable com.datastax.driver.core.ConsistencyLevel consistencyLevel;
|
||||
private @Nullable ConsistencyLevel consistencyLevel;
|
||||
|
||||
/**
|
||||
* If this variable is set to a value, it will be used for setting the {@code retryPolicy} property on statements used
|
||||
* for query processing.
|
||||
*/
|
||||
private @Nullable com.datastax.driver.core.policies.RetryPolicy retryPolicy;
|
||||
private @Deprecated @Nullable RetryPolicy retryPolicy;
|
||||
|
||||
private @Nullable SessionFactory sessionFactory;
|
||||
|
||||
/**
|
||||
* Ensures the Cassandra {@link Session} and exception translator has been propertly set.
|
||||
* Ensures the Cassandra {@link CqlSession} and exception translator has been propertly set.
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
@@ -141,46 +133,72 @@ public class CassandraAccessor implements InitializingBean {
|
||||
* transferring row data that will never be read by the application. Default is -1, indicating to use the CQL driver's
|
||||
* default configuration (i.e. to not pass a specific fetch size setting on to the driver).
|
||||
*
|
||||
* @see Statement#setFetchSize(int)
|
||||
* @see com.datastax.oss.driver.api.core.cql.SimpleStatementBuilder#setPageSize(int)
|
||||
* @deprecated since 3.0, use {@link #setPageSize(int)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setFetchSize(int fetchSize) {
|
||||
this.fetchSize = fetchSize;
|
||||
setPageSize(fetchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fetch size specified for this template.
|
||||
* @deprecated since 3.0, use {@link #getPageSize()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public int getFetchSize() {
|
||||
return this.fetchSize;
|
||||
return getPageSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the page size for this template. This is important for processing large result sets: Setting this higher than
|
||||
* the default value will increase processing speed at the cost of memory consumption; setting this lower can avoid
|
||||
* transferring row data that will never be read by the application. Default is -1, indicating to use the CQL driver's
|
||||
* default configuration (i.e. to not pass a specific page size setting on to the driver).
|
||||
*
|
||||
* @see com.datastax.oss.driver.api.core.cql.SimpleStatementBuilder#setPageSize(int)
|
||||
*/
|
||||
public void setPageSize(int fetchSize) {
|
||||
this.pageSize = fetchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the page size specified for this template.
|
||||
*/
|
||||
public int getPageSize() {
|
||||
return this.pageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the retry policy for this template. This is important for defining behavior when a request fails.
|
||||
*
|
||||
* @see Statement#setRetryPolicy(RetryPolicy)
|
||||
* @see RetryPolicy
|
||||
* @deprecated since 3.0. Use driver execution profiles instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setRetryPolicy(@Nullable RetryPolicy retryPolicy) {
|
||||
this.retryPolicy = retryPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link RetryPolicy} specified for this template.
|
||||
* @deprecated since 3.0. Use driver execution profiles instead.
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public RetryPolicy getRetryPolicy() {
|
||||
return this.retryPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Cassandra {@link Session} used by this template to perform Cassandra data access operations. The
|
||||
* Sets the Cassandra {@link CqlSession} used by this template to perform Cassandra data access operations. The
|
||||
* {@code session} will replace the current {@link #getSessionFactory()} with {@link DefaultSessionFactory}.
|
||||
*
|
||||
* @param session Cassandra {@link Session} used by this template, must not be{@literal null}.
|
||||
* @see com.datastax.driver.core.Session
|
||||
* @param session Cassandra {@link CqlSession} used by this template, must not be{@literal null}.
|
||||
* @see CqlSession
|
||||
* @see DefaultSessionFactory
|
||||
*/
|
||||
public void setSession(Session session) {
|
||||
public void setSession(CqlSession session) {
|
||||
|
||||
Assert.notNull(session, "Session must not be null");
|
||||
|
||||
@@ -188,16 +206,16 @@ public class CassandraAccessor implements InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Cassandra {@link Session} from {@link SessionFactory} used by this template to perform Cassandra data
|
||||
* access operations.
|
||||
* Returns the Cassandra {@link CqlSession} from {@link SessionFactory} used by this template to perform Cassandra
|
||||
* data access operations.
|
||||
*
|
||||
* @return the Cassandra {@link Session} used by this template.
|
||||
* @return the Cassandra {@link CqlSession} used by this template.
|
||||
* @see com.datastax.driver.core.Session
|
||||
* @deprecated since 2.0. This class uses a {@link SessionFactory} to dispatch CQL calls amongst different
|
||||
* {@link Session}s during its lifecycle.
|
||||
* {@link CqlSession}s during its lifecycle.
|
||||
*/
|
||||
@Deprecated
|
||||
public Session getSession() {
|
||||
public CqlSession getSession() {
|
||||
|
||||
Assert.state(getSessionFactory() != null, "SessionFactory was not properly initialized");
|
||||
|
||||
@@ -207,7 +225,7 @@ public class CassandraAccessor implements InitializingBean {
|
||||
/**
|
||||
* Sets the Cassandra {@link SessionFactory} used by this template to perform Cassandra data access operations.
|
||||
*
|
||||
* @param sessionFactory Cassandra {@link Session} used by this template. Must not be{@literal null}.
|
||||
* @param sessionFactory Cassandra {@link CqlSession} used by this template. Must not be{@literal null}.
|
||||
* @since 2.0
|
||||
* @see com.datastax.driver.core.Session
|
||||
*/
|
||||
@@ -231,105 +249,82 @@ public class CassandraAccessor implements InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given CQL Statement (or {@link com.datastax.driver.core.PreparedStatement}), applying statement
|
||||
* settings such as retry policy and consistency level.
|
||||
* Create a {@link SimpleStatement} given {@code cql}.
|
||||
*
|
||||
* @param statement the CQL Statement to prepare
|
||||
* @see #setRetryPolicy(RetryPolicy)
|
||||
* @see #setConsistencyLevel(ConsistencyLevel)
|
||||
* @param cql the CQL query.
|
||||
* @return the {@link SimpleStatement} to use.
|
||||
* @since 3.0
|
||||
*/
|
||||
protected <T extends PreparedStatement> T applyStatementSettings(T statement) {
|
||||
|
||||
ConsistencyLevel consistencyLevel = getConsistencyLevel();
|
||||
|
||||
if (consistencyLevel != null) {
|
||||
statement.setConsistencyLevel(consistencyLevel);
|
||||
}
|
||||
|
||||
RetryPolicy retryPolicy = getRetryPolicy();
|
||||
|
||||
if (retryPolicy != null) {
|
||||
statement.setRetryPolicy(retryPolicy);
|
||||
}
|
||||
|
||||
return statement;
|
||||
protected SimpleStatement newStatement(String cql) {
|
||||
return SimpleStatement.newInstance(cql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given CQL Statement (or {@link com.datastax.driver.core.PreparedStatement}), applying statement
|
||||
* settings such as fetch size, retry policy, and consistency level.
|
||||
* Prepare the given CQL Statement applying statement settings such as page size and consistency level.
|
||||
*
|
||||
* @param statement the CQL Statement to prepare
|
||||
* @see #setFetchSize(int)
|
||||
* @see #setRetryPolicy(RetryPolicy)
|
||||
* @see #setPageSize(int)
|
||||
* @see #setConsistencyLevel(ConsistencyLevel)
|
||||
*/
|
||||
protected <T extends Statement> T applyStatementSettings(T statement) {
|
||||
protected Statement<?> applyStatementSettings(Statement<?> statement) {
|
||||
|
||||
Statement<?> statementToUse = statement;
|
||||
ConsistencyLevel consistencyLevel = getConsistencyLevel();
|
||||
|
||||
if (consistencyLevel != null && statement.getConsistencyLevel() == DEFAULTS.getConsistencyLevel()) {
|
||||
statement.setConsistencyLevel(consistencyLevel);
|
||||
if (getFetchSize() > -1 && statement.getPageSize() < 0) {
|
||||
statementToUse = statementToUse.setPageSize(getFetchSize());
|
||||
}
|
||||
|
||||
int fetchSize = getFetchSize();
|
||||
|
||||
if (fetchSize != -1 && statement.getFetchSize() == DEFAULTS.getFetchSize()) {
|
||||
statement.setFetchSize(fetchSize);
|
||||
if (consistencyLevel != null && statementToUse.getConsistencyLevel() == null) {
|
||||
statementToUse = statementToUse.setConsistencyLevel(getConsistencyLevel());
|
||||
}
|
||||
|
||||
RetryPolicy retryPolicy = getRetryPolicy();
|
||||
|
||||
if (retryPolicy != null && statement.getRetryPolicy() == DEFAULTS.getRetryPolicy()) {
|
||||
statement.setRetryPolicy(retryPolicy);
|
||||
}
|
||||
|
||||
return statement;
|
||||
return statementToUse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the given {@link DriverException} into a generic {@link DataAccessException}.
|
||||
* Translate the given {@link RuntimeException} into a generic {@link DataAccessException}.
|
||||
* <p>
|
||||
* The returned {@link DataAccessException} is supposed to contain the original {@code DriverException} as root cause.
|
||||
* However, client code may not generally rely on this due to {@link DataAccessException}s possibly being caused by
|
||||
* other resource APIs as well. That said, a {@code getRootCause() instanceof DataAccessException} check (and
|
||||
* subsequent cast) is considered reliable when expecting Cassandra-based access to have happened.
|
||||
* The returned {@link DataAccessException} is supposed to contain the original {@code RuntimeException} as root
|
||||
* cause. However, client code may not generally rely on this due to {@link DataAccessException}s possibly being
|
||||
* caused by other resource APIs as well. That said, a {@code getRootCause() instanceof DataAccessException} check
|
||||
* (and subsequent cast) is considered reliable when expecting Cassandra-based access to have happened.
|
||||
*
|
||||
* @param ex the offending {@link DriverException}
|
||||
* @return the DataAccessException, wrapping the {@code DriverException}
|
||||
* @param ex the offending {@link RuntimeException}
|
||||
* @return the DataAccessException, wrapping the {@code RuntimeException}
|
||||
* @see <a href=
|
||||
* "https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#dao-exceptions">Consistent
|
||||
* exception hierarchy</a>
|
||||
* @see DataAccessException
|
||||
*/
|
||||
@Nullable
|
||||
protected DataAccessException translateExceptionIfPossible(DriverException ex) {
|
||||
protected DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
|
||||
Assert.notNull(ex, "DriverException must not be null");
|
||||
Assert.notNull(ex, "RuntimeException must not be null");
|
||||
|
||||
return getExceptionTranslator().translateExceptionIfPossible(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the given {@link DriverException} into a generic {@link DataAccessException}.
|
||||
* Translate the given {@link RuntimeException} into a generic {@link DataAccessException}.
|
||||
* <p>
|
||||
* The returned {@link DataAccessException} is supposed to contain the original {@code DriverException} as root cause.
|
||||
* However, client code may not generally rely on this due to {@link DataAccessException}s possibly being caused by
|
||||
* other resource APIs as well. That said, a {@code getRootCause() instanceof DataAccessException} check (and
|
||||
* subsequent cast) is considered reliable when expecting Cassandra-based access to have happened.
|
||||
* The returned {@link DataAccessException} is supposed to contain the original {@code RuntimeException} as root
|
||||
* cause. However, client code may not generally rely on this due to {@link DataAccessException}s possibly being
|
||||
* caused by other resource APIs as well. That said, a {@code getRootCause() instanceof DataAccessException} check
|
||||
* (and subsequent cast) is considered reliable when expecting Cassandra-based access to have happened.
|
||||
*
|
||||
* @param task readable text describing the task being attempted
|
||||
* @param cql CQL query or update that caused the problem (may be {@literal null})
|
||||
* @param ex the offending {@link DriverException}
|
||||
* @return the DataAccessException, wrapping the {@code DriverException}
|
||||
* @param ex the offending {@link RuntimeException}
|
||||
* @return the DataAccessException, wrapping the {@code RuntimeException}
|
||||
* @see org.springframework.dao.DataAccessException#getRootCause()
|
||||
* @see <a href=
|
||||
* "https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#dao-exceptions">Consistent
|
||||
* exception hierarchy</a>
|
||||
*/
|
||||
protected DataAccessException translate(String task, @Nullable String cql, DriverException ex) {
|
||||
protected DataAccessException translate(String task, @Nullable String cql, RuntimeException ex) {
|
||||
|
||||
Assert.notNull(ex, "DriverException must not be null");
|
||||
Assert.notNull(ex, "RuntimeException must not be null");
|
||||
|
||||
return getExceptionTranslator().translate(task, cql, ex);
|
||||
}
|
||||
@@ -345,49 +340,6 @@ public class CassandraAccessor implements InitializingBean {
|
||||
return new ArgumentPreparedStatementBinder(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the {@link ResultSetExtractor} initialized with and adapting the given
|
||||
* {@link RowCallbackHandler}.
|
||||
*
|
||||
* @param rowCallbackHandler {@link RowCallbackHandler} to adapt as a {@link ResultSetExtractor}.
|
||||
* @return a {@link ResultSetExtractor} implementation adapting an instance of the {@link RowCallbackHandler}.
|
||||
* @see AsyncCqlTemplate.RowCallbackHandlerResultSetExtractor
|
||||
* @see ResultSetExtractor
|
||||
* @see RowCallbackHandler
|
||||
*/
|
||||
protected RowCallbackHandlerResultSetExtractor newResultSetExtractor(RowCallbackHandler rowCallbackHandler) {
|
||||
return new RowCallbackHandlerResultSetExtractor(rowCallbackHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the {@link ResultSetExtractor} initialized with and adapting the given
|
||||
* {@link RowMapper}.
|
||||
*
|
||||
* @param rowMapper {@link RowMapper} to adapt as a {@link ResultSetExtractor}.
|
||||
* @return a {@link ResultSetExtractor} implementation adapting an instance of the {@link RowMapper}.
|
||||
* @see ResultSetExtractor
|
||||
* @see RowMapper
|
||||
* @see RowMapperResultSetExtractor
|
||||
*/
|
||||
protected <T> RowMapperResultSetExtractor<T> newResultSetExtractor(RowMapper<T> rowMapper) {
|
||||
return new RowMapperResultSetExtractor<>(rowMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the {@link ResultSetExtractor} initialized with and adapting the given
|
||||
* {@link RowMapper}.
|
||||
*
|
||||
* @param rowMapper {@link RowMapper} to adapt as a {@link ResultSetExtractor}.
|
||||
* @param rowsExpected number of expected rows in the {@link ResultSet}.
|
||||
* @return a {@link ResultSetExtractor} implementation adapting an instance of the {@link RowMapper}.
|
||||
* @see ResultSetExtractor
|
||||
* @see RowMapper
|
||||
* @see RowMapperResultSetExtractor
|
||||
*/
|
||||
protected <T> RowMapperResultSetExtractor<T> newResultSetExtractor(RowMapper<T> rowMapper, int rowsExpected) {
|
||||
return new RowMapperResultSetExtractor<>(rowMapper, rowsExpected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RowMapper for reading columns as key-value pairs.
|
||||
*
|
||||
@@ -425,28 +377,4 @@ public class CassandraAccessor implements InitializingBean {
|
||||
.map(CqlProvider::getCql) //
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter to enable use of a {@link RowCallbackHandler} inside a {@link ResultSetExtractor}.
|
||||
*/
|
||||
protected static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor<Object> {
|
||||
|
||||
private final RowCallbackHandler rowCallbackHandler;
|
||||
|
||||
protected RowCallbackHandlerResultSetExtractor(RowCallbackHandler rowCallbackHandler) {
|
||||
this.rowCallbackHandler = rowCallbackHandler;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.ResultSetExtractor#extractData(com.datastax.driver.core.ResultSet)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object extractData(ResultSet resultSet) {
|
||||
|
||||
StreamSupport.stream(resultSet.spliterator(), false).forEach(rowCallbackHandler::processRow);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.cql;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -31,8 +30,11 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.datastax.driver.core.WriteType;
|
||||
import com.datastax.driver.core.exceptions.*;
|
||||
import com.datastax.oss.driver.api.core.AllNodesFailedException;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.auth.AuthenticationException;
|
||||
import com.datastax.oss.driver.api.core.metadata.Node;
|
||||
import com.datastax.oss.driver.api.core.servererrors.*;
|
||||
|
||||
/**
|
||||
* Simple {@link PersistenceExceptionTranslator} for Cassandra.
|
||||
@@ -67,18 +69,14 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator {
|
||||
return (DataAccessException) exception;
|
||||
}
|
||||
|
||||
if (!(exception instanceof DriverException)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return translate(null, null, (DriverException) exception);
|
||||
return translate(null, null, exception);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.cql.CQLExceptionTranslator#translate(java.lang.String, java.lang.String, com.datastax.driver.core.exceptions.DriverException)
|
||||
* @see org.springframework.data.cassandra.cql.CQLExceptionTranslator#translate(java.lang.String, java.lang.String, com.datastax.oss.driver.api.core.DriverException)
|
||||
*/
|
||||
@Override
|
||||
public DataAccessException translate(@Nullable String task, @Nullable String cql, DriverException exception) {
|
||||
public DataAccessException translate(@Nullable String task, @Nullable String cql, RuntimeException exception) {
|
||||
|
||||
String message = buildMessage(task, cql, exception);
|
||||
|
||||
@@ -86,9 +84,10 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator {
|
||||
// superclass would match before the subclass!
|
||||
|
||||
if (exception instanceof AuthenticationException) {
|
||||
return new CassandraAuthenticationException(((AuthenticationException) exception).getHost(), message, exception);
|
||||
return new CassandraAuthenticationException(((AuthenticationException) exception).getEndPoint(), message,
|
||||
exception);
|
||||
}
|
||||
|
||||
/* TODO ???
|
||||
if (exception instanceof DriverInternalError) {
|
||||
return new CassandraInternalException(message, exception);
|
||||
}
|
||||
@@ -96,10 +95,11 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator {
|
||||
if (exception instanceof InvalidTypeException) {
|
||||
return new CassandraTypeMismatchException(message, exception);
|
||||
}
|
||||
???
|
||||
*/
|
||||
|
||||
if (exception instanceof ReadTimeoutException) {
|
||||
return new CassandraReadTimeoutException(((ReadTimeoutException) exception).wasDataRetrieved(), message,
|
||||
exception);
|
||||
return new CassandraReadTimeoutException(((ReadTimeoutException) exception).wasDataPresent(), message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof WriteTimeoutException) {
|
||||
@@ -115,20 +115,16 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator {
|
||||
if (exception instanceof UnavailableException) {
|
||||
|
||||
UnavailableException ux = (UnavailableException) exception;
|
||||
return new CassandraInsufficientReplicasAvailableException(ux.getRequiredReplicas(), ux.getAliveReplicas(),
|
||||
message, exception);
|
||||
return new CassandraInsufficientReplicasAvailableException(ux.getRequired(), ux.getAlive(), message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof OverloadedException || exception instanceof BootstrappingException) {
|
||||
return new TransientDataAccessResourceException(message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof AlreadyExistsException) {
|
||||
|
||||
AlreadyExistsException aex = (AlreadyExistsException) exception;
|
||||
|
||||
return aex.wasTableCreation() ? new CassandraTableExistsException(aex.getTable(), message, exception)
|
||||
: new CassandraKeyspaceExistsException(aex.getKeyspace(), message, exception);
|
||||
return new CassandraSchemaElementExistsException(aex.getMessage(), aex);
|
||||
}
|
||||
|
||||
if (exception instanceof InvalidConfigurationInQueryException) {
|
||||
@@ -147,12 +143,8 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator {
|
||||
return new CassandraUnauthorizedException(message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof TraceRetrievalException) {
|
||||
return new CassandraTraceRetrievalException(message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof NoHostAvailableException) {
|
||||
return new CassandraConnectionFailureException(((NoHostAvailableException) exception).getErrors(), message,
|
||||
if (exception instanceof AllNodesFailedException) {
|
||||
return new CassandraConnectionFailureException(((AllNodesFailedException) exception).getErrors(), message,
|
||||
exception);
|
||||
}
|
||||
|
||||
@@ -160,11 +152,11 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator {
|
||||
|
||||
if (CONNECTION_FAILURE_TYPES.contains(exceptionType)) {
|
||||
|
||||
Map<InetSocketAddress, Throwable> errorMap = Collections.emptyMap();
|
||||
Map<Node, Throwable> errorMap = Collections.emptyMap();
|
||||
|
||||
if (exception instanceof CoordinatorException) {
|
||||
CoordinatorException cx = (CoordinatorException) exception;
|
||||
errorMap = Collections.singletonMap(cx.getAddress(), exception);
|
||||
errorMap = Collections.singletonMap(cx.getCoordinator(), exception);
|
||||
}
|
||||
|
||||
return new CassandraConnectionFailureException(errorMap, message, exception);
|
||||
@@ -189,7 +181,7 @@ public class CassandraExceptionTranslator implements CqlExceptionTranslator {
|
||||
* @param ex the offending {@code DriverException}
|
||||
* @return the message {@code String} to use
|
||||
*/
|
||||
protected String buildMessage(@Nullable String task, @Nullable String cql, DriverException ex) {
|
||||
protected String buildMessage(@Nullable String task, @Nullable String cql, RuntimeException ex) {
|
||||
|
||||
if (StringUtils.hasText(task) || StringUtils.hasText(cql)) {
|
||||
return task + "; CQL [" + cql + "]; " + ex.getMessage();
|
||||
|
||||
@@ -20,8 +20,9 @@ import java.util.Map;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
|
||||
import com.datastax.driver.core.ColumnDefinitions;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.ColumnDefinition;
|
||||
import com.datastax.oss.driver.api.core.cql.ColumnDefinitions;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
|
||||
/**
|
||||
* {@link RowMapper} implementation that creates a {@code java.util.Map} for each row, representing all columns as
|
||||
@@ -53,7 +54,8 @@ public class ColumnMapRowMapper implements RowMapper<Map<String, Object>> {
|
||||
Map<String, Object> mapOfColValues = createColumnMap(columnCount);
|
||||
|
||||
for (int i = 0; i < columnCount; i++) {
|
||||
String key = getColumnKey(columnDefinitions.getName(i));
|
||||
ColumnDefinition columnDefinition = columnDefinitions.get(i);
|
||||
String key = getColumnKey(columnDefinition.getName().toString());
|
||||
Object obj = getColumnValue(rs, i);
|
||||
mapOfColValues.put(key, obj);
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.cassandra.core.mapping.UnsupportedCassandraOperationException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
|
||||
/**
|
||||
* Strategy interface for translating between {@link DriverException DriverExceptios} and Spring's data access
|
||||
* Strategy interface for translating between {@link RuntimeException driver exceptions} and Spring's data access
|
||||
* strategy-agnostic {@link DataAccessException} hierarchy.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
@@ -34,7 +34,7 @@ import com.datastax.driver.core.exceptions.DriverException;
|
||||
public interface CqlExceptionTranslator extends PersistenceExceptionTranslator {
|
||||
|
||||
/**
|
||||
* Translate the given {@link DriverException} into a generic {@link DataAccessException}.
|
||||
* Translate the given {@link RuntimeException} into a generic {@link DataAccessException}.
|
||||
* <p>
|
||||
* The returned {@link DataAccessException} is supposed to contain the original {@code DriverException} as root cause.
|
||||
* However, client code may not generally rely on this due to {@link DataAccessException}s possibly being caused by
|
||||
@@ -44,10 +44,10 @@ public interface CqlExceptionTranslator extends PersistenceExceptionTranslator {
|
||||
* @param task readable text describing the task being attempted.
|
||||
* @param cql CQL query or update that caused the problem (may be {@literal null}).
|
||||
* @param ex the offending {@link DriverException}.
|
||||
* @return the DataAccessException, wrapping the {@link DriverException}.
|
||||
* @return the DataAccessException, wrapping the {@link RuntimeException}.
|
||||
* @see org.springframework.dao.DataAccessException#getRootCause()
|
||||
*/
|
||||
default DataAccessException translate(@Nullable String task, @Nullable String cql, DriverException ex) {
|
||||
default DataAccessException translate(@Nullable String task, @Nullable String cql, RuntimeException ex) {
|
||||
|
||||
DataAccessException translated = translateExceptionIfPossible(ex);
|
||||
return translated == null ? new UnsupportedCassandraOperationException("Cannot translate exception", ex)
|
||||
|
||||
@@ -20,9 +20,6 @@ import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.KeyspaceMetadata;
|
||||
import com.datastax.driver.core.TableMetadata;
|
||||
|
||||
/**
|
||||
* This encapsulates the logic for CQL quoted and unquoted identifiers.
|
||||
* <p>
|
||||
@@ -269,4 +266,14 @@ public final class CqlIdentifier implements Comparable<CqlIdentifier>, Serializa
|
||||
public String toString() {
|
||||
return toCql();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Cassandra driver {@link com.datastax.oss.driver.api.core.CqlIdentifier} from this {@link CqlIdentifier}.
|
||||
*
|
||||
* @return the {@link com.datastax.oss.driver.api.core.CqlIdentifier} from this {@link CqlIdentifierIdentifier}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public com.datastax.oss.driver.api.core.CqlIdentifier toCqlIdentifier() {
|
||||
return com.datastax.oss.driver.api.core.CqlIdentifier.fromCql(this.identifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@ import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.ResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
|
||||
/**
|
||||
* Interface specifying a basic set of CQL operations. Implemented by {@link CqlTemplate}. Not often used directly, but
|
||||
@@ -40,14 +40,14 @@ import com.datastax.driver.core.Statement;
|
||||
public interface CqlOperations {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with a plain com.datastax.driver.core.Session
|
||||
// Methods dealing with a plain com.datastax.oss.driver.api.core.CqlSession
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Execute a CQL data access operation, implemented as callback action working on a
|
||||
* {@link com.datastax.driver.core.Session}. This allows for implementing arbitrary data access operations, within
|
||||
* Spring's managed CQL environment: that is, converting CQL
|
||||
* {@link com.datastax.driver.core.exceptions.DriverException}s into Spring's {@link DataAccessException} hierarchy.
|
||||
* Spring's managed CQL environment: that is, converting CQL {@link com.datastax.oss.driver.api.core.DriverException}s
|
||||
* into Spring's {@link DataAccessException} hierarchy.
|
||||
* <p>
|
||||
* The callback action can return a result object, for example a domain object or a collection of domain objects.
|
||||
*
|
||||
@@ -101,7 +101,7 @@ public interface CqlOperations {
|
||||
* Execute a CQL data access operation, implemented as callback action working on a CQL {@link PreparedStatement}.
|
||||
* This allows for implementing arbitrary data access operations on a single Statement, within Spring's managed CQL
|
||||
* environment: that is, participating in Spring-managed transactions and converting CQL
|
||||
* {@link com.datastax.driver.core.exceptions.DriverException}s into Spring's {@link DataAccessException} hierarchy.
|
||||
* {@link com.datastax.oss.driver.api.core.DriverException}s into Spring's {@link DataAccessException} hierarchy.
|
||||
* <p>
|
||||
* The callback action can return a result object, for example a domain object or a collection of domain objects.
|
||||
*
|
||||
@@ -482,7 +482,7 @@ public interface CqlOperations {
|
||||
Iterable<Row> queryForRows(String cql, Object... args) throws DataAccessException;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.Statement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.Statement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -492,7 +492,7 @@ public interface CqlOperations {
|
||||
* @return boolean value whether the statement was applied.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
boolean execute(Statement statement) throws DataAccessException;
|
||||
boolean execute(Statement<?> statement) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static CQL, reading the {@link ResultSet} with a {@link ResultSetExtractor}.
|
||||
@@ -507,7 +507,7 @@ public interface CqlOperations {
|
||||
* @see #query(String, ResultSetExtractor, Object...)
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(Statement statement, ResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
|
||||
<T> T query(Statement<?> statement, ResultSetExtractor<T> resultSetExtractor) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static CQL, reading the {@link ResultSet} on a per-row basis with a
|
||||
@@ -521,7 +521,7 @@ public interface CqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #query(String, RowCallbackHandler, Object[])
|
||||
*/
|
||||
void query(Statement statement, RowCallbackHandler rowCallbackHandler) throws DataAccessException;
|
||||
void query(Statement<?> statement, RowCallbackHandler rowCallbackHandler) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static CQL, mapping each row to a Java object via a {@link RowMapper}.
|
||||
@@ -535,7 +535,7 @@ public interface CqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #query(String, RowMapper, Object[])
|
||||
*/
|
||||
<T> List<T> query(Statement statement, RowMapper<T> rowMapper) throws DataAccessException;
|
||||
<T> List<T> query(Statement<?> statement, RowMapper<T> rowMapper) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result {@link List}, given static CQL.
|
||||
@@ -552,7 +552,7 @@ public interface CqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForList(String, Object[])
|
||||
*/
|
||||
List<Map<String, Object>> queryForList(Statement statement) throws DataAccessException;
|
||||
List<Map<String, Object>> queryForList(Statement<?> statement) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result {@link List}, given static CQL.
|
||||
@@ -571,7 +571,7 @@ public interface CqlOperations {
|
||||
* @see #queryForList(String, Class, Object[])
|
||||
* @see SingleColumnRowMapper
|
||||
*/
|
||||
<T> List<T> queryForList(Statement statement, Class<T> elementType) throws DataAccessException;
|
||||
<T> List<T> queryForList(Statement<?> statement, Class<T> elementType) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result Map, given static CQL.
|
||||
@@ -590,7 +590,7 @@ public interface CqlOperations {
|
||||
* @see #queryForMap(String, Object[])
|
||||
* @see ColumnMapRowMapper
|
||||
*/
|
||||
Map<String, Object> queryForMap(Statement statement) throws DataAccessException;
|
||||
Map<String, Object> queryForMap(Statement<?> statement) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a result object, given static CQL.
|
||||
@@ -610,7 +610,7 @@ public interface CqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForObject(String, Class, Object[])
|
||||
*/
|
||||
<T> T queryForObject(Statement statement, Class<T> requiredType) throws DataAccessException;
|
||||
<T> T queryForObject(Statement<?> statement, Class<T> requiredType) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query given static CQL, mapping a single result row to a Java object via a {@link RowMapper}.
|
||||
@@ -626,7 +626,7 @@ public interface CqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForObject(String, RowMapper, Object[])
|
||||
*/
|
||||
<T> T queryForObject(Statement statement, RowMapper<T> rowMapper) throws DataAccessException;
|
||||
<T> T queryForObject(Statement<?> statement, RowMapper<T> rowMapper) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for a ResultSet, given static CQL.
|
||||
@@ -642,7 +642,7 @@ public interface CqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForResultSet(String, Object[])
|
||||
*/
|
||||
ResultSet queryForResultSet(Statement statement) throws DataAccessException;
|
||||
ResultSet queryForResultSet(Statement<?> statement) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a query for Rows, given static CQL.
|
||||
@@ -658,10 +658,10 @@ public interface CqlOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
* @see #queryForResultSet(String, Object[])
|
||||
*/
|
||||
Iterable<Row> queryForRows(Statement statement) throws DataAccessException;
|
||||
Iterable<Row> queryForRows(Statement<?> statement) throws DataAccessException;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.PreparedStatement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.PreparedStatement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -672,14 +672,13 @@ public interface CqlOperations {
|
||||
* @return boolean value whether the statement was applied.
|
||||
* @throws DataAccessException if there is any problem executing the query.
|
||||
*/
|
||||
// TODO: Interferes with execute(session callback lambda)
|
||||
boolean execute(PreparedStatementCreator psc) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Execute a CQL data access operation, implemented as callback action working on a CQL {@link PreparedStatement}.
|
||||
* This allows for implementing arbitrary data access operations on a single {@link PreparedStatement}, within
|
||||
* Spring's managed CQL environment: that is, participating in Spring-managed transactions and converting CQL
|
||||
* {@link com.datastax.driver.core.exceptions.DriverException}s into Spring's {@link DataAccessException} hierarchy.
|
||||
* {@link com.datastax.oss.driver.api.core.DriverException}s into Spring's {@link DataAccessException} hierarchy.
|
||||
* <p>
|
||||
* The callback action can return a result object, for example a domain object or a collection of domain objects.
|
||||
*
|
||||
|
||||
@@ -18,8 +18,8 @@ package org.springframework.data.cassandra.core.cql;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.DataAccessUtils;
|
||||
@@ -27,20 +27,18 @@ import org.springframework.data.cassandra.SessionFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.driver.core.BoundStatement;
|
||||
import com.datastax.driver.core.Host;
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.SimpleStatement;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.ResultSet;
|
||||
import com.datastax.oss.driver.api.core.cql.Row;
|
||||
import com.datastax.oss.driver.api.core.cql.Statement;
|
||||
import com.datastax.oss.driver.api.core.metadata.Node;
|
||||
|
||||
/**
|
||||
* <b>This is the central class in the CQL core package.</b> It simplifies the use of CQL and helps to avoid common
|
||||
* errors. It executes core CQL workflow, leaving application code to provide CQL and extract results. This class
|
||||
* executes CQL queries or updates, initiating iteration over {@link ResultSet}s and catching {@link DriverException}
|
||||
* executes CQL queries or updates, initiating iteration over {@link ResultSet}s and catching {@link RuntimeException}
|
||||
* exceptions and translating them to the generic, more informative exception hierarchy defined in the
|
||||
* {@code org.springframework.dao} package.
|
||||
* <p>
|
||||
@@ -49,10 +47,10 @@ import com.datastax.driver.core.exceptions.DriverException;
|
||||
* and any necessary parameters. The {@link ResultSetExtractor} interface extracts values from a {@link ResultSet}. See
|
||||
* also {@link PreparedStatementBinder} and {@link RowMapper} for two popular alternative callback interfaces.
|
||||
* <p>
|
||||
* Can be used within a service implementation via direct instantiation with a {@link Session} reference, or get
|
||||
* prepared in an application context and given to services as bean reference. Note: The {@link Session} should always
|
||||
* be configured as a bean in the application context, in the first case given to the service directly, in the second
|
||||
* case to the prepared template.
|
||||
* Can be used within a service implementation via direct instantiation with a {@link CqlSession} reference, or get
|
||||
* prepared in an application context and given to services as bean reference. Note: The {@link CqlSession} should
|
||||
* always be configured as a bean in the application context, in the first case given to the service directly, in the
|
||||
* second case to the prepared template.
|
||||
* <p>
|
||||
* Because this class is parameterizable by the callback interfaces and the
|
||||
* {@link org.springframework.dao.support.PersistenceExceptionTranslator} interface, there should be no need to subclass
|
||||
@@ -89,13 +87,12 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
public CqlTemplate() {}
|
||||
|
||||
/**
|
||||
* Create a new {@link CqlTemplate} initialized with the given {@link Session}.
|
||||
* Create a new {@link CqlTemplate} initialized with the given {@link CqlSession}.
|
||||
*
|
||||
* @param session the active Cassandra {@link Session}.
|
||||
* @throws IllegalStateException if {@link Session} is {@literal null}.
|
||||
* @see com.datastax.driver.core.Session
|
||||
* @param session the active Cassandra {@link CqlSession}.
|
||||
* @throws IllegalStateException if {@link CqlSession} is {@literal null}.
|
||||
*/
|
||||
public CqlTemplate(Session session) {
|
||||
public CqlTemplate(CqlSession session) {
|
||||
|
||||
Assert.notNull(session, "Session must not be null");
|
||||
|
||||
@@ -116,7 +113,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with a plain com.datastax.driver.core.Session
|
||||
// Methods dealing with a plain com.datastax.oss.driver.api.core.CqlSession
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
@@ -167,7 +164,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
logger.debug("Executing CQL Statement [{}]", cql);
|
||||
}
|
||||
|
||||
SimpleStatement statement = applyStatementSettings(new SimpleStatement(cql));
|
||||
Statement<?> statement = applyStatementSettings(newStatement(cql));
|
||||
|
||||
ResultSet results = getCurrentSession().execute(statement);
|
||||
|
||||
@@ -263,15 +260,15 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with com.datastax.driver.core.Statement
|
||||
// Methods dealing with com.datastax.oss.driver.api.core.cql.Statement
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#execute(com.datastax.driver.core.Statement)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#execute(com.datastax.oss.driver.api.core.cql.Statement)
|
||||
*/
|
||||
@Override
|
||||
public boolean execute(Statement statement) throws DataAccessException {
|
||||
public boolean execute(Statement<?> statement) throws DataAccessException {
|
||||
|
||||
Assert.notNull(statement, "CQL Statement must not be null");
|
||||
|
||||
@@ -280,10 +277,10 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#query(com.datastax.driver.core.Statement, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#query(com.datastax.oss.driver.api.core.cql.Statement, org.springframework.data.cassandra.core.cql.ResultSetExtractor)
|
||||
*/
|
||||
@Override
|
||||
public <T> T query(Statement statement, ResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
|
||||
public <T> T query(Statement<?> statement, ResultSetExtractor<T> resultSetExtractor) throws DataAccessException {
|
||||
|
||||
Assert.notNull(statement, "CQL Statement must not be null");
|
||||
Assert.notNull(resultSetExtractor, "ResultSetExtractor must not be null");
|
||||
@@ -301,87 +298,87 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#query(com.datastax.driver.core.Statement, org.springframework.data.cassandra.core.cql.RowCallbackHandler)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#query(com.datastax.oss.driver.api.core.cql.Statement, org.springframework.data.cassandra.core.cql.RowCallbackHandler)
|
||||
*/
|
||||
@Override
|
||||
public void query(Statement statement, RowCallbackHandler rowCallbackHandler) throws DataAccessException {
|
||||
public void query(Statement<?> statement, RowCallbackHandler rowCallbackHandler) throws DataAccessException {
|
||||
query(statement, newResultSetExtractor(rowCallbackHandler));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#query(com.datastax.driver.core.Statement, org.springframework.data.cassandra.core.cql.RowMapper)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#query(com.datastax.oss.driver.api.core.cql.Statement, org.springframework.data.cassandra.core.cql.RowMapper)
|
||||
*/
|
||||
@Override
|
||||
public <T> List<T> query(Statement statement, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
public <T> List<T> query(Statement<?> statement, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
// noinspection ConstantConditions
|
||||
return query(statement, newResultSetExtractor(rowMapper));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForList(com.datastax.driver.core.Statement)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForList(com.datastax.oss.driver.api.core.cql.Statement)
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> queryForList(Statement statement) throws DataAccessException {
|
||||
public List<Map<String, Object>> queryForList(Statement<?> statement) throws DataAccessException {
|
||||
// noinspection ConstantConditions
|
||||
return query(statement, newResultSetExtractor(newColumnMapRowMapper()));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForList(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForList(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> List<T> queryForList(Statement statement, Class<T> elementType) throws DataAccessException {
|
||||
public <T> List<T> queryForList(Statement<?> statement, Class<T> elementType) throws DataAccessException {
|
||||
// noinspection ConstantConditions
|
||||
return query(statement, newResultSetExtractor(newSingleColumnRowMapper(elementType)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForMap(com.datastax.driver.core.Statement)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForMap(com.datastax.oss.driver.api.core.cql.Statement)
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> queryForMap(Statement statement) throws DataAccessException {
|
||||
public Map<String, Object> queryForMap(Statement<?> statement) throws DataAccessException {
|
||||
// noinspection ConstantConditions
|
||||
return queryForObject(statement, newColumnMapRowMapper());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForObject(com.datastax.driver.core.Statement, java.lang.Class)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForObject(com.datastax.oss.driver.api.core.cql.Statement, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> T queryForObject(Statement statement, Class<T> requiredType) throws DataAccessException {
|
||||
public <T> T queryForObject(Statement<?> statement, Class<T> requiredType) throws DataAccessException {
|
||||
return queryForObject(statement, newSingleColumnRowMapper(requiredType));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForObject(com.datastax.driver.core.Statement, org.springframework.data.cassandra.core.cql.RowMapper)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForObject(com.datastax.oss.driver.api.core.cql.Statement, org.springframework.data.cassandra.core.cql.RowMapper)
|
||||
*/
|
||||
@Override
|
||||
public <T> T queryForObject(Statement statement, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
public <T> T queryForObject(Statement<?> statement, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return DataAccessUtils.requiredSingleResult(query(statement, newResultSetExtractor(rowMapper)));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForResultSet(com.datastax.driver.core.Statement)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForResultSet(com.datastax.oss.driver.api.core.cql.Statement)
|
||||
*/
|
||||
@Override
|
||||
public ResultSet queryForResultSet(Statement statement) throws DataAccessException {
|
||||
public ResultSet queryForResultSet(Statement<?> statement) throws DataAccessException {
|
||||
// noinspection ConstantConditions
|
||||
return query(statement, rs -> rs);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForRows(com.datastax.driver.core.Statement)
|
||||
* @see org.springframework.data.cassandra.core.cqlOperations#queryForRows(com.datastax.oss.driver.api.core.cql.Statement)
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Row> queryForRows(Statement statement) throws DataAccessException {
|
||||
public Iterable<Row> queryForRows(Statement<?> statement) throws DataAccessException {
|
||||
return () -> queryForResultSet(statement).iterator();
|
||||
}
|
||||
|
||||
@@ -445,10 +442,9 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
logger.debug("Preparing statement [{}] using {}", toCql(preparedStatementCreator), preparedStatementCreator);
|
||||
}
|
||||
|
||||
Session session = getCurrentSession();
|
||||
CqlSession session = getCurrentSession();
|
||||
|
||||
return action.doInPreparedStatement(session,
|
||||
applyStatementSettings(preparedStatementCreator.createPreparedStatement(session)));
|
||||
return action.doInPreparedStatement(session, preparedStatementCreator.createPreparedStatement(session));
|
||||
|
||||
} catch (DriverException e) {
|
||||
throw translateException("PreparedStatementCallback", toCql(preparedStatementCreator), e);
|
||||
@@ -505,7 +501,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
logger.debug("Preparing statement [{}] using {}", toCql(preparedStatementCreator), preparedStatementCreator);
|
||||
}
|
||||
|
||||
Session session = getCurrentSession();
|
||||
CqlSession session = getCurrentSession();
|
||||
|
||||
PreparedStatement preparedStatement = preparedStatementCreator.createPreparedStatement(session);
|
||||
|
||||
@@ -513,7 +509,7 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
logger.debug("Executing prepared statement [{}]", preparedStatement);
|
||||
}
|
||||
|
||||
BoundStatement boundStatement = applyStatementSettings(
|
||||
Statement<?> boundStatement = applyStatementSettings(
|
||||
psb != null ? psb.bindValues(preparedStatement) : preparedStatement.bind());
|
||||
|
||||
ResultSet results = session.execute(boundStatement);
|
||||
@@ -700,14 +696,28 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private Set<Host> getHosts() {
|
||||
return getCurrentSession().getCluster().getMetadata().getAllHosts();
|
||||
private Collection<Node> getHosts() {
|
||||
return getCurrentSession().getMetadata().getNodes().values();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Implementation hooks and helper methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Translate the given {@link RuntimeException} into a generic {@link DataAccessException}.
|
||||
*
|
||||
* @param task readable text describing the task being attempted
|
||||
* @param cql CQL query or update that caused the problem (may be {@literal null})
|
||||
* @param RuntimeException the offending {@code RuntimeException}.
|
||||
* @return the exception translation {@link Function}
|
||||
* @see CqlProvider
|
||||
*/
|
||||
protected DataAccessException translateException(String task, @Nullable String cql,
|
||||
RuntimeException RuntimeException) {
|
||||
return translate(task, cql, RuntimeException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CQL-based {@link PreparedStatementCreator} using the CQL passed in. By default, we'll create an
|
||||
* {@link SimplePreparedStatementCreator}. This method allows for the creation to be overridden by subclasses.
|
||||
@@ -720,19 +730,49 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the given {@link DriverException} into a generic {@link DataAccessException}.
|
||||
* Constructs a new instance of the {@link ResultSetExtractor} initialized with and adapting the given
|
||||
* {@link RowCallbackHandler}.
|
||||
*
|
||||
* @param task readable text describing the task being attempted
|
||||
* @param cql CQL query or update that caused the problem (may be {@literal null})
|
||||
* @param driverException the offending {@code RuntimeException}.
|
||||
* @return the exception translation {@link Function}
|
||||
* @see CqlProvider
|
||||
* @param rowCallbackHandler {@link RowCallbackHandler} to adapt as a {@link ResultSetExtractor}.
|
||||
* @return a {@link ResultSetExtractor} implementation adapting an instance of the {@link RowCallbackHandler}.
|
||||
* @see AsyncCqlTemplate.AsyncRowCallbackHandlerResultSetExtractor
|
||||
* @see ResultSetExtractor
|
||||
* @see RowCallbackHandler
|
||||
*/
|
||||
protected DataAccessException translateException(String task, @Nullable String cql, DriverException driverException) {
|
||||
return translate(task, cql, driverException);
|
||||
protected RowCallbackHandlerResultSetExtractor newResultSetExtractor(RowCallbackHandler rowCallbackHandler) {
|
||||
return new RowCallbackHandlerResultSetExtractor(rowCallbackHandler);
|
||||
}
|
||||
|
||||
private Session getCurrentSession() {
|
||||
/**
|
||||
* Constructs a new instance of the {@link ResultSetExtractor} initialized with and adapting the given
|
||||
* {@link RowMapper}.
|
||||
*
|
||||
* @param rowMapper {@link RowMapper} to adapt as a {@link ResultSetExtractor}.
|
||||
* @return a {@link ResultSetExtractor} implementation adapting an instance of the {@link RowMapper}.
|
||||
* @see ResultSetExtractor
|
||||
* @see RowMapper
|
||||
* @see RowMapperResultSetExtractor
|
||||
*/
|
||||
protected <T> RowMapperResultSetExtractor<T> newResultSetExtractor(RowMapper<T> rowMapper) {
|
||||
return new RowMapperResultSetExtractor<>(rowMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the {@link ResultSetExtractor} initialized with and adapting the given
|
||||
* {@link RowMapper}.
|
||||
*
|
||||
* @param rowMapper {@link RowMapper} to adapt as a {@link ResultSetExtractor}.
|
||||
* @param rowsExpected number of expected rows in the {@link ResultSet}.
|
||||
* @return a {@link ResultSetExtractor} implementation adapting an instance of the {@link RowMapper}.
|
||||
* @see ResultSetExtractor
|
||||
* @see RowMapper
|
||||
* @see RowMapperResultSetExtractor
|
||||
*/
|
||||
protected <T> RowMapperResultSetExtractor<T> newResultSetExtractor(RowMapper<T> rowMapper, int rowsExpected) {
|
||||
return new RowMapperResultSetExtractor<>(rowMapper, rowsExpected);
|
||||
}
|
||||
|
||||
private CqlSession getCurrentSession() {
|
||||
|
||||
SessionFactory sessionFactory = getSessionFactory();
|
||||
|
||||
@@ -741,4 +781,28 @@ public class CqlTemplate extends CassandraAccessor implements CqlOperations {
|
||||
return sessionFactory.getSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter to enable use of a {@link RowCallbackHandler} inside a {@link ResultSetExtractor}.
|
||||
*/
|
||||
protected static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor<Object> {
|
||||
|
||||
private final RowCallbackHandler rowCallbackHandler;
|
||||
|
||||
protected RowCallbackHandlerResultSetExtractor(RowCallbackHandler rowCallbackHandler) {
|
||||
this.rowCallbackHandler = rowCallbackHandler;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.cassandra.core.cql.ResultSetExtractor#extractData(com.datastax.driver.core.ResultSet)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object extractData(ResultSet resultSet) {
|
||||
|
||||
StreamSupport.stream(resultSet.spliterator(), false).forEach(rowCallbackHandler::processRow);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.cql;
|
||||
|
||||
import io.netty.util.concurrent.ImmediateExecutor;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.FailureCallback;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
import org.springframework.util.concurrent.SuccessCallback;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
||||
/**
|
||||
* Adapter class to adapt Guava's {@link com.google.common.util.concurrent.ListenableFuture} into a Spring
|
||||
* {@link ListenableFuture}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
public class GuavaListenableFutureAdapter<T> implements ListenableFuture<T> {
|
||||
|
||||
private final com.google.common.util.concurrent.ListenableFuture<T> adaptee;
|
||||
|
||||
private final ListenableFuture<T> future;
|
||||
|
||||
/**
|
||||
* Create a new {@link GuavaListenableFutureAdapter} given a Guava
|
||||
* {@link com.google.common.util.concurrent.ListenableFuture} and a {@link PersistenceExceptionTranslator}.
|
||||
*
|
||||
* @param adaptee must not be {@literal null}.
|
||||
* @param persistenceExceptionTranslator must not be {@literal null}.
|
||||
*/
|
||||
public GuavaListenableFutureAdapter(com.google.common.util.concurrent.ListenableFuture<T> adaptee,
|
||||
PersistenceExceptionTranslator persistenceExceptionTranslator) {
|
||||
|
||||
Assert.notNull(adaptee, "ListenableFuture must not be null");
|
||||
Assert.notNull(persistenceExceptionTranslator, "PersistenceExceptionTranslator must not be null");
|
||||
|
||||
this.adaptee = adaptee;
|
||||
this.future = adaptListenableFuture(adaptee, persistenceExceptionTranslator);
|
||||
}
|
||||
|
||||
private static <T> ListenableFuture<T> adaptListenableFuture(
|
||||
com.google.common.util.concurrent.ListenableFuture<T> guavaFuture,
|
||||
PersistenceExceptionTranslator exceptionTranslator) {
|
||||
|
||||
SettableListenableFuture<T> settableFuture = new SettableListenableFuture<>();
|
||||
|
||||
Futures.addCallback(guavaFuture, new FutureCallback<T>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable T result) {
|
||||
settableFuture.set(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
if (t instanceof RuntimeException) {
|
||||
DataAccessException dataAccessException = exceptionTranslator
|
||||
.translateExceptionIfPossible((RuntimeException) t);
|
||||
|
||||
if (dataAccessException != null) {
|
||||
settableFuture.setException(dataAccessException);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
settableFuture.setException(t);
|
||||
}
|
||||
}, ImmediateExecutor.INSTANCE);
|
||||
|
||||
return settableFuture;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.util.concurrent.ListenableFuture#addCallback(org.springframework.util.concurrent.ListenableFutureCallback)
|
||||
*/
|
||||
@Override
|
||||
public void addCallback(ListenableFutureCallback<? super T> callback) {
|
||||
future.addCallback(callback);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.util.concurrent.ListenableFuture#addCallback(org.springframework.util.concurrent.SuccessCallback, org.springframework.util.concurrent.FailureCallback)
|
||||
*/
|
||||
@Override
|
||||
public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) {
|
||||
future.addCallback(successCallback, failureCallback);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.util.concurrent.Future#cancel(boolean)
|
||||
*/
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return adaptee.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.util.concurrent.Future#isCancelled()
|
||||
*/
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return adaptee.isCancelled();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.util.concurrent.Future#isDone()
|
||||
*/
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return future.isDone();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.util.concurrent.Future#get()
|
||||
*/
|
||||
@Override
|
||||
public T get() throws InterruptedException, ExecutionException {
|
||||
return future.get();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.util.concurrent.Future#get(long, java.util.concurrent.TimeUnit)
|
||||
*/
|
||||
@Override
|
||||
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return future.get(timeout, unit);
|
||||
}
|
||||
}
|
||||
@@ -17,14 +17,13 @@ package org.springframework.data.cassandra.core.cql;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.datastax.driver.core.Host;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.metadata.Node;
|
||||
|
||||
/**
|
||||
* An interface used by {@link CqlTemplate} for mapping {@link Host}s of a {@link com.datastax.driver.core.Metadata} on
|
||||
* a per-item basis.. Implementations of this interface perform the actual work of mapping each host to a result object,
|
||||
* but don't need to worry about exception handling. {@link DriverException} will be caught and handled by the calling
|
||||
* {@link CqlTemplate}.
|
||||
* An interface used by {@link CqlTemplate} for mapping {@link Node}s of metadata on a per-item basis.. Implementations
|
||||
* of this interface perform the actual work of mapping each host to a result object, but don't need to worry about
|
||||
* exception handling. {@link DriverException} will be caught and handled by the calling {@link CqlTemplate}.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
@@ -34,13 +33,12 @@ import com.datastax.driver.core.exceptions.DriverException;
|
||||
public interface HostMapper<T> {
|
||||
|
||||
/**
|
||||
* Implementations must implement this method to map each {@link Host} in the
|
||||
* {@link com.datastax.driver.core.Metadata}.
|
||||
* Implementations must implement this method to map each {@link Node}.
|
||||
*
|
||||
* @param hosts the {@link Iterable} of {@link Host}s to map, must not be {@literal null}.
|
||||
* @param hosts the {@link Iterable} of {@link Node}s to map, must not be {@literal null}.
|
||||
* @return the result objects for the given hosts.
|
||||
* @throws DriverException if a {@link DriverException} is encountered mapping values (that is, there's no need to
|
||||
* catch {@link DriverException}).
|
||||
*/
|
||||
Collection<T> mapHosts(Iterable<Host> hosts) throws DriverException;
|
||||
Collection<T> mapHosts(Iterable<Node> hosts) throws DriverException;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.datastax.oss.driver.api.core.CqlIdentifier;
|
||||
|
||||
/**
|
||||
* This encapsulates the logic for keyspace identifiers.
|
||||
* <p/>
|
||||
@@ -28,7 +30,9 @@ import org.springframework.util.Assert;
|
||||
* @see #toCql()
|
||||
* @see #toString()
|
||||
* @author Matthew T. Adams
|
||||
* @deprecated since 3.0, use {@link com.datastax.oss.driver.api.core.CqlIdentifier}.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class KeyspaceIdentifier implements Comparable<KeyspaceIdentifier> {
|
||||
|
||||
public static final String REGEX = "(?i)[a-z][\\w]{0,47}";
|
||||
@@ -137,4 +141,14 @@ public final class KeyspaceIdentifier implements Comparable<KeyspaceIdentifier>
|
||||
public int compareTo(KeyspaceIdentifier that) {
|
||||
return this.identifier.compareTo(that.identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link CqlIdentifier} from this {@link KeyspaceIdentifier}.
|
||||
*
|
||||
* @return the {@link CqlIdentifier} from this {@link KeyspaceIdentifier}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public CqlIdentifier toCqlIdentifier() {
|
||||
return CqlIdentifier.fromCql(this.identifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.cassandra.core.cql;
|
||||
|
||||
import com.datastax.driver.core.BoundStatement;
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.oss.driver.api.core.DriverException;
|
||||
import com.datastax.oss.driver.api.core.cql.BoundStatement;
|
||||
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
|
||||
|
||||
/**
|
||||
* General callback interface used by the {@link CqlTemplate} and {@link ReactiveCqlTemplate} classes.
|
||||
@@ -35,7 +35,7 @@ import com.datastax.driver.core.exceptions.DriverException;
|
||||
* @author David Webb
|
||||
* @author Mark Paluch
|
||||
* @see CqlTemplate#query(String, PreparedStatementBinder, ResultSetExtractor)
|
||||
* @see AsyncCqlTemplate#query(AsyncPreparedStatementCreator, PreparedStatementBinder, ResultSetExtractor)
|
||||
* @see AsyncCqlTemplate#query(String, PreparedStatementBinder, AsyncResultSetExtractor)
|
||||
* @see ReactiveCqlTemplate#query(String, PreparedStatementBinder, ReactiveResultSetExtractor)
|
||||
*/
|
||||
@FunctionalInterface
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user