diff --git a/build.gradle b/build.gradle
index f47f1d4fe..a98d09edf 100644
--- a/build.gradle
+++ b/build.gradle
@@ -74,13 +74,14 @@ javadoc {
ext.tmpDir = file("${buildDir}/api-work")
configure(options) {
- stylesheetFile = file("${srcDir}/spring-javadoc.css")
- overview = "${srcDir}/overview.html"
+ //stylesheetFile = file("${srcDir}/spring-javadoc.css")
+ //overview = "${srcDir}/overview.html"
docFilesSubDirs = true
outputLevel = org.gradle.external.javadoc.JavadocOutputLevel.QUIET
breakIterator = true
showFromProtected()
groups = [
+ 'Spring Cassandra' : ['org.springframework.cassandra*'],
'Spring Data Cassandra' : ['org.springframework.data.cassandra*'],
]
diff --git a/src/main/java/org/springframework/cassandra/core/CachedPreparedStatementCreator.java b/src/main/java/org/springframework/cassandra/core/CachedPreparedStatementCreator.java
new file mode 100644
index 000000000..90fdba895
--- /dev/null
+++ b/src/main/java/org/springframework/cassandra/core/CachedPreparedStatementCreator.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2011-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cassandra.core;
+
+import org.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;
+
+/**
+ * Created a PreparedStatement and retrieved the PreparedStatement from cache if the statement has been prepared
+ * previously. In general, this creator should be used over the {@link SimplePreparedStatementCreator} as it provides
+ * better performance.
+ *
+ *
+ * There is overhead in Cassandra when Preparing a Statement. This is negligible on a single data center configuration,
+ * but when your cluster spans multiple data centers, preparing the same statement over and over again is not necessary
+ * and causes performance issues in high throughput use cases.
+ *
+ *
+ * @author David Webb
+ *
+ */
+public class CachedPreparedStatementCreator implements PreparedStatementCreator, CqlProvider {
+
+ private static Logger log = LoggerFactory.getLogger(CachedPreparedStatementCreator.class);
+
+ private final String cql;
+
+ private PreparedStatement cache;
+
+ /**
+ * Create a CachedPreparedStatementCreator from the provided CQL.
+ *
+ * @param cql
+ */
+ public CachedPreparedStatementCreator(String cql) {
+ Assert.notNull(cql, "CQL is required to create a PreparedStatement");
+ this.cql = cql;
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.cassandra.core.PreparedStatementCreator#createPreparedStatement(com.datastax.driver.core.Session)
+ */
+ @Override
+ public PreparedStatement createPreparedStatement(Session session) throws DriverException {
+ if (cache == null) {
+ log.debug("PreparedStatement cache is null, preparing new Statement");
+ cache = session.prepare(getCql());
+ } else {
+ log.debug("Using cached PreparedStatement");
+ }
+ return cache;
+ }
+
+ /* (non-Javadoc)
+ * @see org.springframework.cassandra.core.CqlProvider#getCql()
+ */
+ @Override
+ public String getCql() {
+ return this.cql;
+ }
+
+}
diff --git a/src/main/java/org/springframework/cassandra/core/CassandraOperations.java b/src/main/java/org/springframework/cassandra/core/CassandraOperations.java
index fbd3653d6..991c9ec95 100644
--- a/src/main/java/org/springframework/cassandra/core/CassandraOperations.java
+++ b/src/main/java/org/springframework/cassandra/core/CassandraOperations.java
@@ -22,6 +22,7 @@ import java.util.Map;
import org.springframework.dao.DataAccessException;
import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Session;
/**
* Operations for interacting with Cassandra at the lowest level. This interface provides Exception Translation.
@@ -36,7 +37,7 @@ public interface CassandraOperations {
* SessionCallback can decide whether or not to execute() or executeAsync() the operation.
*
* @param sessionCallback
- * @return
+ * @return Type defined in the SessionCallback
*/
T execute(SessionCallback sessionCallback) throws DataAccessException;
@@ -48,19 +49,19 @@ public interface CassandraOperations {
void execute(final String cql) throws DataAccessException;
/**
- * Executes the supplied CQL Query Asynchrously and returns nothing.
+ * Executes the supplied CQL Query Asynchronously and returns nothing.
*
- * @param cql
+ * @param cql The CQL Statement to execute
*/
void executeAsynchronously(final String cql) throws DataAccessException;
/**
- * Executes the provided CQL Query, and extracts the results with the ResultSetExtractor
+ * Executes the provided CQL Query, and extracts the results with the ResultSetExtractor.
*
* @param cql The Query
- * @param rse The implementation for extracting the results
+ * @param rse The implementation for extracting the ResultSet
*
- * @return
+ * @return Type specified in the ResultSetExtractor
* @throws DataAccessException
*/
T query(final String cql, ResultSetExtractor rse) throws DataAccessException;
@@ -69,72 +70,332 @@ public interface CassandraOperations {
* Executes the provided CQL Query asynchronously, and extracts the results with the ResultSetFutureExtractor
*
* @param cql The Query
- * @param rse The implementation for extracting the results
+ * @param rse The implementation for extracting the future results
* @return
* @throws DataAccessException
*/
T queryAsynchronously(final String cql, ResultSetFutureExtractor rse) throws DataAccessException;
+ /**
+ * Executes the provided CQL Query, and then processes the results with the RowCallbackHandler.
+ *
+ * @param cql The Query
+ * @param rch The implementation for processing the rows returned.
+ * @throws DataAccessException
+ */
void query(final String cql, RowCallbackHandler rch) throws DataAccessException;
+ /**
+ * Processes the ResultSet through the RowCallbackHandler and return nothing. This is used internal to the Template
+ * for core operations, but is made available through Operations in the event you have a ResultSet to process. The
+ * ResultsSet could come from a ResultSetFuture after an asynchronous query.
+ *
+ * @param resultSet Results to process
+ * @param rch RowCallbackHandler with the processing implementation
+ * @throws DataAccessException
+ */
void process(ResultSet resultSet, RowCallbackHandler rch) throws DataAccessException;
+ /**
+ * Executes the provided CQL Query, and maps all Rows returned with the supplied RowMapper.
+ *
+ * @param cql The Query
+ * @param rowMapper The implementation for mapping all rows
+ * @return List of processed by the RowMapper
+ * @throws DataAccessException
+ */
List query(final String cql, RowMapper rowMapper) throws DataAccessException;
+ /**
+ * Processes the ResultSet through the RowMapper and returns the List of mapped Rows. This is used internal to the
+ * Template for core operations, but is made available through Operations in the event you have a ResultSet to
+ * process. The ResultsSet could come from a ResultSetFuture after an asynchronous query.
+ *
+ * @param resultSet Results to process
+ * @param rowMapper RowMapper with the processing implementation
+ * @return List of generated by the RowMapper
+ * @throws DataAccessException
+ */
List process(ResultSet resultSet, RowMapper rowMapper) throws DataAccessException;
+ /**
+ * Executes the provided CQL Query, and maps ONE Row returned with the supplied RowMapper.
+ *
+ *
+ * This expects only ONE row to be returned. More than one Row will cause an Exception to be thrown.
+ *
+ *
+ * @param cql The Query
+ * @param rowMapper The implementation for convert the Row to
+ * @return Object
+ * @throws DataAccessException
+ */
T queryForObject(final String cql, RowMapper rowMapper) throws DataAccessException;
+ /**
+ * Process a ResultSet through a RowMapper. This is used internal to the Template for core operations, but is made
+ * available through Operations in the event you have a ResultSet to process. The ResultsSet could come from a
+ * ResultSetFuture after an asynchronous query.
+ *
+ * @param resultSet
+ * @param rowMapper
+ * @return
+ * @throws DataAccessException
+ */
T processOne(ResultSet resultSet, RowMapper rowMapper) throws DataAccessException;
+ /**
+ * Executes the provided query and tries to return the first column of the first Row as a Class.
+ *
+ * @param cql The Query
+ * @param requiredType Valid Class that Cassandra Data Types can be converted to.
+ * @return The Object - item [0,0] in the result table of the query.
+ * @throws DataAccessException
+ */
T queryForObject(final String cql, Class requiredType) throws DataAccessException;
+ /**
+ * Process a ResultSet, trying to convert the first columns of the first Row to Class. This is used internal to the
+ * Template for core operations, but is made available through Operations in the event you have a ResultSet to
+ * process. The ResultsSet could come from a ResultSetFuture after an asynchronous query.
+ *
+ * @param resultSet
+ * @param requiredType
+ * @return
+ * @throws DataAccessException
+ */
T processOne(ResultSet resultSet, Class requiredType) throws DataAccessException;
+ /**
+ * Executes the provided CQL Query and maps ONE Row to a basic Map of Strings and Objects. If more than one Row
+ * is returned from the Query, an exception will be thrown.
+ *
+ * @param cql The Query
+ * @return Map representing the results of the Query
+ * @throws DataAccessException
+ */
Map queryForMap(final String cql) throws DataAccessException;
+ /**
+ * Process a ResultSet with ONE Row and convert to a Map. This is used internal to the Template for core
+ * operations, but is made available through Operations in the event you have a ResultSet to process. The ResultsSet
+ * could come from a ResultSetFuture after an asynchronous query.
+ *
+ * @param resultSet
+ * @return
+ * @throws DataAccessException
+ */
Map processMap(ResultSet resultSet) throws DataAccessException;
+ /**
+ * Executes the provided CQL and returns all values in the first column of the Results as a List of the Type in the
+ * second argument.
+ *
+ * @param cql The Query
+ * @param elementType Type to cast the data values to
+ * @return List of elementType
+ * @throws DataAccessException
+ */
List queryForList(final String cql, Class elementType) throws DataAccessException;
+ /**
+ * Process a ResultSet and convert the first column of the results to a List. This is used internal to the Template
+ * for core operations, but is made available through Operations in the event you have a ResultSet to process. The
+ * ResultsSet could come from a ResultSetFuture after an asynchronous query.
+ *
+ * @param resultSet
+ * @param elementType
+ * @return
+ * @throws DataAccessException
+ */
List processList(ResultSet resultSet, Class elementType) throws DataAccessException;
+ /**
+ * Executes the provided CQL and converts the results to a basic List of Maps. Each element in the List represents a
+ * Row returned from the Query. Each Row's columns are put into the map as column/value.
+ *
+ * @param cql The Query
+ * @return List of Maps with the query results
+ * @throws DataAccessException
+ */
List