diff --git a/build.gradle b/build.gradle index a98d09edf..3f9fd0a9f 100644 --- a/build.gradle +++ b/build.gradle @@ -69,14 +69,15 @@ sourceCompatibility = 1.6 targetCompatibility = 1.6 javadoc { - ext.srcDir = file("${projectDir}/docs/src/api") - destinationDir = file("${buildDir}/api") + ext.srcDir = file("${projectDir}/src/main/doc") + ext.destinationDir = file("${buildDir}/api") ext.tmpDir = file("${buildDir}/api-work") configure(options) { - //stylesheetFile = file("${srcDir}/spring-javadoc.css") + stylesheetFile = file("${srcDir}/spring-javadoc.css") //overview = "${srcDir}/overview.html" docFilesSubDirs = true + outputLevel = org.gradle.external.javadoc.JavadocOutputLevel.QUIET breakIterator = true showFromProtected() @@ -94,6 +95,16 @@ javadoc { exclude "org/springframework/data/cassandra/config/**" } + logger.error("BuildDir => ${buildDir}"); + logger.error("DestDir => ${destinationDir}"); + logger.error("ExtDestDir => ${ext.destinationDir}"); + + copy { + from "src/main/doc/resources" + into "${ext.destinationDir}/resources" + include '**/*' + } + title = "${rootProject.description} ${version} API" } diff --git a/src/main/doc/resources/background.gif b/src/main/doc/resources/background.gif new file mode 100644 index 000000000..f471940fd Binary files /dev/null and b/src/main/doc/resources/background.gif differ diff --git a/src/main/doc/resources/tab.gif b/src/main/doc/resources/tab.gif new file mode 100644 index 000000000..1a73a83be Binary files /dev/null and b/src/main/doc/resources/tab.gif differ diff --git a/src/main/doc/resources/titlebar.gif b/src/main/doc/resources/titlebar.gif new file mode 100644 index 000000000..17443b3e1 Binary files /dev/null and b/src/main/doc/resources/titlebar.gif differ diff --git a/src/main/doc/resources/titlebar_end.gif b/src/main/doc/resources/titlebar_end.gif new file mode 100644 index 000000000..3ad78d461 Binary files /dev/null and b/src/main/doc/resources/titlebar_end.gif differ diff --git a/src/main/doc/spring-javadoc.css b/src/main/doc/spring-javadoc.css new file mode 100644 index 000000000..0aeaa97fe --- /dev/null +++ b/src/main/doc/spring-javadoc.css @@ -0,0 +1,474 @@ +/* Javadoc style sheet */ +/* +Overall document style +*/ +body { + background-color:#ffffff; + color:#353833; + font-family:Arial, Helvetica, sans-serif; + font-size:76%; + margin:0; +} +a:link, a:visited { + text-decoration:none; + color:#4c6b87; +} +a:hover, a:focus { + text-decoration:none; + color:#bb7a2a; +} +a:active { + text-decoration:none; + color:#4c6b87; +} +a[name] { + color:#353833; +} +a[name]:hover { + text-decoration:none; + color:#353833; +} +pre { + font-size:1.3em; +} +h1 { + font-size:1.8em; +} +h2 { + font-size:1.5em; +} +h3 { + font-size:1.4em; +} +h4 { + font-size:1.3em; +} +h5 { + font-size:1.2em; +} +h6 { + font-size:1.1em; +} +ul { + list-style-type:disc; +} +code, tt { + font-size:1.2em; +} +dt code { + font-size:1.2em; +} +table tr td dt code { + font-size:1.2em; + vertical-align:top; +} +sup { + font-size:.6em; +} +/* +Document title and Copyright styles +*/ +.clear { + clear:both; + height:0px; + overflow:hidden; +} +.aboutLanguage { + float:right; + padding:0px 21px; + font-size:.8em; + z-index:200; + margin-top:-7px; +} +.legalCopy { + margin-left:.5em; +} +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color:#FFFFFF; + text-decoration:none; +} +.bar a:hover, .bar a:focus { + color:#bb7a2a; +} +.tab { + background-color:#0066FF; + background-image:url(resources/titlebar.gif); + background-position:left top; + background-repeat:no-repeat; + color:#ffffff; + padding:8px; + width:5em; + font-weight:bold; +} +/* +Navigation bar styles +*/ +.bar { + background-image:url(resources/background.gif); + background-repeat:repeat-x; + color:#FFFFFF; + padding:.8em .5em .4em .8em; + height:auto;/*height:1.8em;*/ + font-size:1em; + margin:0; +} +.topNav { + background-image:url(resources/background.gif); + background-repeat:repeat-x; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; +} +.bottomNav { + margin-top:10px; + background-image:url(resources/background.gif); + background-repeat:repeat-x; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; +} +.subNav { + background-color:#dee3e9; + border-bottom:1px solid #9eadc0; + float:left; + width:100%; + overflow:hidden; +} +.subNav div { + clear:left; + float:left; + padding:0 0 5px 6px; +} +ul.navList, ul.subNavList { + float:left; + margin:0 25px 0 0; + padding:0; +} +ul.navList li{ + list-style:none; + float:left; + padding:3px 6px; +} +ul.subNavList li{ + list-style:none; + float:left; + font-size:90%; +} +.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { + color:#FFFFFF; + text-decoration:none; +} +.topNav a:hover, .bottomNav a:hover { + text-decoration:none; + color:#bb7a2a; +} +.navBarCell1Rev { + background-image:url(resources/tab.gif); + background-color:#a88834; + color:#FFFFFF; + margin: auto 5px; + border:1px solid #c9aa44; +} +/* +Page header and footer styles +*/ +.header, .footer { + clear:both; + margin:0 20px; + padding:5px 0 0 0; +} +.indexHeader { + margin:10px; + position:relative; +} +.indexHeader h1 { + font-size:1.3em; +} +.title { + color:#2c4557; + margin:10px 0; +} +.subTitle { + margin:5px 0 0 0; +} +.header ul { + margin:0 0 25px 0; + padding:0; +} +.footer ul { + margin:20px 0 5px 0; +} +.header ul li, .footer ul li { + list-style:none; + font-size:1.2em; +} +/* +Heading styles +*/ +div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { + background-color:#dee3e9; + border-top:1px solid #9eadc0; + border-bottom:1px solid #9eadc0; + margin:0 0 6px -8px; + padding:2px 5px; +} +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color:#dee3e9; + border-top:1px solid #9eadc0; + border-bottom:1px solid #9eadc0; + margin:0 0 6px -8px; + padding:2px 5px; +} +ul.blockList ul.blockList li.blockList h3 { + padding:0; + margin:15px 0; +} +ul.blockList li.blockList h2 { + padding:0px 0 20px 0; +} +/* +Page layout container styles +*/ +.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { + clear:both; + padding:10px 20px; + position:relative; +} +.indexContainer { + margin:10px; + position:relative; + font-size:1.0em; +} +.indexContainer h2 { + font-size:1.1em; + padding:0 0 3px 0; +} +.indexContainer ul { + margin:0; + padding:0; +} +.indexContainer ul li { + list-style:none; +} +.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { + font-size:1.1em; + font-weight:bold; + margin:10px 0 0 0; + color:#4E4E4E; +} +.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { + margin:10px 0 10px 20px; +} +.serializedFormContainer dl.nameValue dt { + margin-left:1px; + font-size:1.1em; + display:inline; + font-weight:bold; +} +.serializedFormContainer dl.nameValue dd { + margin:0 0 0 1px; + font-size:1.1em; + display:inline; +} +/* +List styles +*/ +ul.horizontal li { + display:inline; + font-size:0.9em; +} +ul.inheritance { + margin:0; + padding:0; +} +ul.inheritance li { + display:inline; + list-style:none; +} +ul.inheritance li ul.inheritance { + margin-left:15px; + padding-left:15px; + padding-top:1px; +} +ul.blockList, ul.blockListLast { + margin:10px 0 10px 0; + padding:0; +} +ul.blockList li.blockList, ul.blockListLast li.blockList { + list-style:none; + margin-bottom:25px; +} +ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { + padding:0px 20px 5px 10px; + border:1px solid #9eadc0; + background-color:#f9f9f9; +} +ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { + padding:0 0 5px 8px; + background-color:#ffffff; + border:1px solid #9eadc0; + border-top:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + margin-left:0; + padding-left:0; + padding-bottom:15px; + border:none; + border-bottom:1px solid #9eadc0; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + list-style:none; + border-bottom:none; + padding-bottom:0; +} +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top:0; + margin-bottom:1px; +} +/* +Table styles +*/ +.contentContainer table, .classUseContainer table, .constantValuesContainer table { + border-bottom:1px solid #9eadc0; + width:100%; +} +.contentContainer ul li table, .classUseContainer ul li table, .constantValuesContainer ul li table { + width:100%; +} +.contentContainer .description table, .contentContainer .details table { + border-bottom:none; +} +.contentContainer ul li table th.colOne, .contentContainer ul li table th.colFirst, .contentContainer ul li table th.colLast, .classUseContainer ul li table th, .constantValuesContainer ul li table th, .contentContainer ul li table td.colOne, .contentContainer ul li table td.colFirst, .contentContainer ul li table td.colLast, .classUseContainer ul li table td, .constantValuesContainer ul li table td{ + vertical-align:top; + padding-right:20px; +} +.contentContainer ul li table th.colLast, .classUseContainer ul li table th.colLast,.constantValuesContainer ul li table th.colLast, +.contentContainer ul li table td.colLast, .classUseContainer ul li table td.colLast,.constantValuesContainer ul li table td.colLast, +.contentContainer ul li table th.colOne, .classUseContainer ul li table th.colOne, +.contentContainer ul li table td.colOne, .classUseContainer ul li table td.colOne { + padding-right:3px; +} +.overviewSummary caption, .packageSummary caption, .contentContainer ul.blockList li.blockList caption, .summary caption, .classUseContainer caption, .constantValuesContainer caption { + position:relative; + text-align:left; + background-repeat:no-repeat; + color:#FFFFFF; + font-weight:bold; + clear:none; + overflow:hidden; + padding:0px; + margin:0px; +} +caption a:link, caption a:hover, caption a:active, caption a:visited { + color:#FFFFFF; +} +.overviewSummary caption span, .packageSummary caption span, .contentContainer ul.blockList li.blockList caption span, .summary caption span, .classUseContainer caption span, .constantValuesContainer caption span { + white-space:nowrap; + padding-top:8px; + padding-left:8px; + display:block; + float:left; + background-image:url(resources/titlebar.gif); + height:18px; +} +.overviewSummary .tabEnd, .packageSummary .tabEnd, .contentContainer ul.blockList li.blockList .tabEnd, .summary .tabEnd, .classUseContainer .tabEnd, .constantValuesContainer .tabEnd { + width:10px; + background-image:url(resources/titlebar_end.gif); + background-repeat:no-repeat; + background-position:top right; + position:relative; + float:left; +} +ul.blockList ul.blockList li.blockList table { + margin:0 0 12px 0px; + width:100%; +} +.tableSubHeadingColor { + background-color: #EEEEFF; +} +.altColor { + background-color:#eeeeef; +} +.rowColor { + background-color:#ffffff; +} +.overviewSummary td, .packageSummary td, .contentContainer ul.blockList li.blockList td, .summary td, .classUseContainer td, .constantValuesContainer td { + text-align:left; + padding:3px 3px 3px 7px; +} +th.colFirst, th.colLast, th.colOne, .constantValuesContainer th { + background:#dee3e9; + border-top:1px solid #9eadc0; + border-bottom:1px solid #9eadc0; + text-align:left; + padding:3px 3px 3px 7px; +} +td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { + font-weight:bold; +} +td.colFirst, th.colFirst { + border-left:1px solid #9eadc0; + white-space:nowrap; +} +td.colLast, th.colLast { + border-right:1px solid #9eadc0; +} +td.colOne, th.colOne { + border-right:1px solid #9eadc0; + border-left:1px solid #9eadc0; +} +table.overviewSummary { + padding:0px; + margin-left:0px; +} +table.overviewSummary td.colFirst, table.overviewSummary th.colFirst, +table.overviewSummary td.colOne, table.overviewSummary th.colOne { + width:25%; + vertical-align:middle; +} +table.packageSummary td.colFirst, table.overviewSummary th.colFirst { + width:25%; + vertical-align:middle; +} +/* +Content styles +*/ +.description pre { + margin-top:0; +} +.deprecatedContent { + margin:0; + padding:10px 0; +} +.docSummary { + padding:0; +} +/* +Formatting effect styles +*/ +.sourceLineNo { + color:green; + padding:0 30px 0 0; +} +h1.hidden { + visibility:hidden; + overflow:hidden; + font-size:.9em; +} +.block { + display:block; + margin:3px 0 0 0; +} +.strong { + font-weight:bold; +} diff --git a/src/main/java/org/springframework/cassandra/core/CachedPreparedStatementCreator.java b/src/main/java/org/springframework/cassandra/core/CachedPreparedStatementCreator.java deleted file mode 100644 index 90fdba895..000000000 --- a/src/main/java/org/springframework/cassandra/core/CachedPreparedStatementCreator.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2011-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cassandra.core; - -import org.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 991c9ec95..3d5d8cf41 100644 --- a/src/main/java/org/springframework/cassandra/core/CassandraOperations.java +++ b/src/main/java/org/springframework/cassandra/core/CassandraOperations.java @@ -398,4 +398,44 @@ public interface CassandraOperations { */ Session getSession(); + /** + * This is an operation designed for high performance writes. The cql is used to create a PreparedStatement once, then + * all row values are bound to the single PreparedStatement and executed against the Session. + * + *

+ * This is used internally by the other ingest() methods, but can be used if you want to write your own RowIterator. + * The Object[] length returned by the next() implementation must match the number of bind variables in the CQL. + *

+ * + * @param cql The CQL + * @param rowIterator Implementation to provide the Object[] to be bound to the CQL. + */ + void ingest(String cql, RowIterator rowIterator); + + /** + * This is an operation designed for high performance writes. The cql is used to create a PreparedStatement once, then + * all row values are bound to the single PreparedStatement and executed against the Session. + * + *

+ * The List length must match the number of bind variables in the CQL. + *

+ * + * @param cql The CQL + * @param rows List of List with data to bind to the CQL. + */ + void ingest(String cql, List> rows); + + /** + * This is an operation designed for high performance writes. The cql is used to create a PreparedStatement once, then + * all row values are bound to the single PreparedStatement and executed against the Session. + * + *

+ * The Object[] length of the nested array must match the number of bind variables in the CQL. + *

+ * + * @param cql The CQL + * @param rows Object array of Object array of values to bind to the CQL. + */ + void ingest(String cql, Object[][] rows); + } diff --git a/src/main/java/org/springframework/cassandra/core/CassandraTemplate.java b/src/main/java/org/springframework/cassandra/core/CassandraTemplate.java index 0e599926d..d428ec884 100644 --- a/src/main/java/org/springframework/cassandra/core/CassandraTemplate.java +++ b/src/main/java/org/springframework/cassandra/core/CassandraTemplate.java @@ -559,4 +559,60 @@ public class CassandraTemplate extends CassandraAccessor implements CassandraOpe } }); } + + /* (non-Javadoc) + * @see org.springframework.cassandra.core.CassandraOperations#execute(java.lang.String, org.springframework.cassandra.core.RowProvider, int) + */ + @Override + public void ingest(String cql, RowIterator rowIterator) { + + PreparedStatement preparedStatement = getSession().prepare(cql); + + while (rowIterator.hasNext()) { + getSession().execute(preparedStatement.bind(rowIterator.next())); + } + + } + + /* (non-Javadoc) + * @see org.springframework.cassandra.core.CassandraOperations#execute(java.lang.String, java.util.List) + */ + @Override + public void ingest(String cql, List> rows) { + + Assert.notNull(rows); + Assert.notEmpty(rows); + + Object[][] values = new Object[rows.size()][]; + int i = 0; + for (List row : rows) { + values[i++] = row.toArray(); + } + + ingest(cql, values); + + } + + /* (non-Javadoc) + * @see org.springframework.cassandra.core.CassandraOperations#execute(java.lang.String, java.lang.Object[][]) + */ + @Override + public void ingest(String cql, final Object[][] rows) { + + ingest(cql, new RowIterator() { + + int index = 0; + + @Override + public Object[] next() { + return rows[index++]; + } + + @Override + public boolean hasNext() { + return index < rows.length; + } + + }); + } } \ No newline at end of file diff --git a/src/main/java/org/springframework/cassandra/core/CqlParameter.java b/src/main/java/org/springframework/cassandra/core/CqlParameter.java deleted file mode 100644 index bfd5db193..000000000 --- a/src/main/java/org/springframework/cassandra/core/CqlParameter.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2011-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cassandra.core; - -import java.util.LinkedList; -import java.util.List; - -import org.springframework.util.Assert; - -import com.datastax.driver.core.DataType; - -/** - * @author David Webb - * - */ -public class CqlParameter { - - /** The name of the parameter, if any */ - private String name; - - /** SQL type constant from {@link DataType} */ - private final DataType type; - - /** The scale to apply in case of a NUMERIC or DECIMAL type, if any */ - private Integer scale; - - /** - * Create a new anonymous CqlParameter, supplying the SQL type. - * - * @param type Cassandra Data Type of the parameter according to {@link DataType} - */ - public CqlParameter(DataType type) { - this.type = type; - } - - /** - * Create a new anonymous CqlParameter, supplying the SQL type. - * - * @param type Cassandra Data Type of the parameter according to {@link DataType} - * @param scale the number of digits after the decimal point - */ - public CqlParameter(DataType type, int scale) { - this.type = type; - this.scale = scale; - } - - /** - * Create a new CqlParameter, supplying name and SQL type. - * - * @param name name of the parameter, as used in input and output maps - * @param type Cassandra Data Type of the parameter according to {@link DataType} - */ - public CqlParameter(String name, DataType type) { - this.name = name; - this.type = type; - } - - /** - * Create a new CqlParameter, supplying name and SQL type. - * - * @param name name of the parameter, as used in input and output maps - * @param type Cassandra Data Type of the parameter according to {@link DataType} - * @param scale the number of digits after the decimal point (for DECIMAL and NUMERIC types) - */ - public CqlParameter(String name, DataType type, int scale) { - this.name = name; - this.type = type; - this.scale = scale; - } - - /** - * Copy constructor. - * - * @param otherParam the CqlParameter object to copy from - */ - public CqlParameter(CqlParameter otherParam) { - Assert.notNull(otherParam, "CqlParameter object must not be null"); - this.name = otherParam.name; - this.type = otherParam.type; - this.scale = otherParam.scale; - } - - /** - * Return the name of the parameter. - */ - public String getName() { - return this.name; - } - - /** - * Return the SQL type of the parameter. - */ - public DataType getType() { - return this.type; - } - - /** - * Return the scale of the parameter, if any. - */ - public Integer getScale() { - return this.scale; - } - - /** - * Return whether this parameter holds input values that should be set before execution even if they are {@code null}. - *

- * This implementation always returns {@code true}. - */ - public boolean isInputValueProvided() { - return true; - } - - /** - * Convert a list of JDBC types, as defined in {@code java.sql.Types}, to a List of CqlParameter objects as used in - * this package. - */ - public static List sqlTypesToAnonymousParameterList(DataType[] types) { - List result = new LinkedList(); - if (types != null) { - for (DataType type : types) { - result.add(new CqlParameter(type)); - } - } - return result; - } -} diff --git a/src/main/java/org/springframework/cassandra/core/CqlParameterValue.java b/src/main/java/org/springframework/cassandra/core/CqlParameterValue.java deleted file mode 100644 index c2932815f..000000000 --- a/src/main/java/org/springframework/cassandra/core/CqlParameterValue.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2011-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cassandra.core; - -import com.datastax.driver.core.DataType; - -/** - * @author David Webb - * - */ -public class CqlParameterValue extends CqlParameter { - - private final Object value; - - /** - * Create a new CqlParameterValue, supplying the Cassandra DataType. - * - * @param type Cassandra Data Type of the parameter according to {@link DataType} - * @param value the value object - */ - public CqlParameterValue(DataType type, Object value) { - super(type); - this.value = value; - } - - /** - * Create a new CqlParameterValue, supplying the Cassandra DataType. - * - * @param type Cassandra Data Type of the parameter according to {@link DataType} - * @param scale the number of digits after the decimal point (for DECIMAL and NUMERIC types) - * @param value the value object - */ - public CqlParameterValue(DataType type, int scale, Object value) { - super(type, scale); - this.value = value; - } - - /** - * Create a new CqlParameterValue based on the given CqlParameter declaration. - * - * @param declaredParam the declared CqlParameter to define a value for - * @param value the value object - */ - public CqlParameterValue(CqlParameter declaredParam, Object value) { - super(declaredParam); - this.value = value; - } - - /** - * Return the value object that this parameter value holds. - */ - public Object getValue() { - return this.value; - } -} diff --git a/src/main/java/org/springframework/cassandra/core/PreparedStatementCreatorFactory.java b/src/main/java/org/springframework/cassandra/core/PreparedStatementCreatorFactory.java deleted file mode 100644 index 974b0436e..000000000 --- a/src/main/java/org/springframework/cassandra/core/PreparedStatementCreatorFactory.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright 2011-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.cassandra.core; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.util.Assert; - -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.PreparedStatement; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.exceptions.DriverException; - -/** - * @author David Webb - * - */ -public class PreparedStatementCreatorFactory { - - /** - * The CQL, which won't change when the parameters change - */ - private final String cql; - - /** List of CqlParameter objects. May not be {@code null}. */ - private final List declaredParameters; - - /** - * Create a new factory. - */ - public PreparedStatementCreatorFactory(String cql) { - this.cql = cql; - this.declaredParameters = new LinkedList(); - } - - /** - * Create a new factory with the given CQL and parameters. - * - * @param cql CQL - * @param declaredParameters list of {@link CqlParameter} objects - * @see CqlParameter - */ - public PreparedStatementCreatorFactory(String cql, List declaredParameters) { - this.cql = cql; - this.declaredParameters = declaredParameters; - } - - /** - * Return a new PreparedStatementBinder for the given parameters. - * - * @param params list of parameters (may be {@code null}) - */ - public PreparedStatementBinder newPreparedStatementBinder(List params) { - return new PreparedStatementCreatorImpl(params != null ? params : Collections.emptyList()); - } - - /** - * Return a new PreparedStatementBinder for the given parameters. - * - * @param params the parameter array (may be {@code null}) - */ - public PreparedStatementBinder newPreparedStatementBinder(Object[] params) { - return new PreparedStatementCreatorImpl(params != null ? Arrays.asList(params) : Collections.emptyList()); - } - - /** - * Return a new PreparedStatementCreator for the given parameters. - * - * @param params list of parameters (may be {@code null}) - */ - public PreparedStatementCreator newPreparedStatementCreator(List params) { - return new PreparedStatementCreatorImpl(params != null ? params : Collections.emptyList()); - } - - /** - * Return a new PreparedStatementCreator for the given parameters. - * - * @param params the parameter array (may be {@code null}) - */ - public PreparedStatementCreator newPreparedStatementCreator(Object[] params) { - return new PreparedStatementCreatorImpl(params != null ? Arrays.asList(params) : Collections.emptyList()); - } - - /** - * Return a new PreparedStatementCreator for the given parameters. - * - * @param sqlToUse the actual SQL statement to use (if different from the factory's, for example because of named - * parameter expanding) - * @param params the parameter array (may be {@code null}) - */ - public PreparedStatementCreator newPreparedStatementCreator(String sqlToUse, Object[] params) { - return new PreparedStatementCreatorImpl(sqlToUse, params != null ? Arrays.asList(params) : Collections.emptyList()); - } - - /** - * PreparedStatementCreator implementation returned by this class. - */ - private class PreparedStatementCreatorImpl implements PreparedStatementCreator, PreparedStatementBinder, CqlProvider { - - private final String actualCql; - - private final List parameters; - - public PreparedStatementCreatorImpl(List parameters) { - this(cql, parameters); - } - - /** - * @param actualCql - * @param parameters - */ - public PreparedStatementCreatorImpl(String actualCql, List parameters) { - this.actualCql = actualCql; - Assert.notNull(parameters, "Parameters List must not be null"); - this.parameters = parameters; - if (this.parameters.size() != declaredParameters.size()) { - Set names = new HashSet(); - for (int i = 0; i < parameters.size(); i++) { - Object param = parameters.get(i); - if (param instanceof CqlParameterValue) { - names.add(((CqlParameterValue) param).getName()); - } else { - names.add("Parameter #" + i); - } - } - if (names.size() != declaredParameters.size()) { - throw new InvalidDataAccessApiUsageException("CQL [" + cql + "]: given " + names.size() - + " parameters but expected " + declaredParameters.size()); - } - } - } - - /* (non-Javadoc) - * @see org.springframework.cassandra.core.PreparedStatementCreator#createPreparedStatement(com.datastax.driver.core.Session) - */ - @Override - public PreparedStatement createPreparedStatement(Session session) throws DriverException { - return session.prepare(this.actualCql); - } - - /* (non-Javadoc) - * @see org.springframework.cassandra.core.PreparedStatementBinder#bindValues(com.datastax.driver.core.PreparedStatement) - */ - @Override - public BoundStatement bindValues(PreparedStatement ps) throws DriverException { - if (this.parameters == null || this.parameters.size() == 0) { - return ps.bind(); - } - - // Test the type of the first value - Object v = this.parameters.get(0); - Object[] values; - if (v instanceof CqlParameterValue) { - LinkedList valuesList = new LinkedList(); - for (Object value : this.parameters) { - valuesList.add(((CqlParameterValue) value).getValue()); - } - values = valuesList.toArray(); - } else { - values = this.parameters.toArray(); - } - - return ps.bind(values); - } - - /* (non-Javadoc) - * @see org.springframework.cassandra.core.CqlProvider#getCql() - */ - @Override - public String getCql() { - return cql; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("PreparedStatementCreatorFactory.PreparedStatementCreatorImpl: cql=["); - sb.append(cql).append("]; parameters=").append(this.parameters); - return sb.toString(); - } - - } -} diff --git a/src/main/java/org/springframework/cassandra/core/RowIterator.java b/src/main/java/org/springframework/cassandra/core/RowIterator.java new file mode 100644 index 000000000..9fb98ce57 --- /dev/null +++ b/src/main/java/org/springframework/cassandra/core/RowIterator.java @@ -0,0 +1,29 @@ +/* + * 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; + + +/** + * @author David Webb + * + */ +public interface RowIterator { + + Object[] next(); + + boolean hasNext(); + +} diff --git a/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/AbstractEmbeddedCassandraIntegrationTest.java b/src/test/java/org/springframework/cassandra/test/integration/AbstractEmbeddedCassandraIntegrationTest.java similarity index 70% rename from src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/AbstractEmbeddedCassandraIntegrationTest.java rename to src/test/java/org/springframework/cassandra/test/integration/AbstractEmbeddedCassandraIntegrationTest.java index f6046ac02..c636965fc 100644 --- a/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/AbstractEmbeddedCassandraIntegrationTest.java +++ b/src/test/java/org/springframework/cassandra/test/integration/AbstractEmbeddedCassandraIntegrationTest.java @@ -1,4 +1,4 @@ -package org.springframework.cassandra.test.integration.core.cql.generator; +package org.springframework.cassandra.test.integration; import java.io.IOException; import java.util.UUID; @@ -6,6 +6,7 @@ import java.util.UUID; import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.thrift.transport.TTransportException; import org.cassandraunit.utils.EmbeddedCassandraServerHelper; +import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -15,12 +16,20 @@ import com.datastax.driver.core.Session; public abstract class AbstractEmbeddedCassandraIntegrationTest { + protected final static String CASSANDRA_CONFIG = "cassandra.yaml"; + protected final static String CASSANDRA_HOST = "localhost"; + protected final static int CASSANDRA_NATIVE_PORT = 9042; + @BeforeClass public static void beforeClass() throws ConfigurationException, TTransportException, IOException, InterruptedException { - EmbeddedCassandraServerHelper.startEmbeddedCassandra("cassandra.yaml"); + EmbeddedCassandraServerHelper.startEmbeddedCassandra(CASSANDRA_CONFIG); } + /** + * Whether to clear the cluster before the next test. + */ + protected boolean clear = true; /** * Whether to connect to Cassandra. */ @@ -46,7 +55,7 @@ public abstract class AbstractEmbeddedCassandraIntegrationTest { } public Cluster cluster() { - return Cluster.builder().addContactPoint("localhost").withPort(9042).build(); + return Cluster.builder().addContactPoint(CASSANDRA_HOST).withPort(CASSANDRA_NATIVE_PORT).build(); } @Before @@ -64,8 +73,17 @@ public abstract class AbstractEmbeddedCassandraIntegrationTest { session.execute("CREATE KEYSPACE " + keyspace + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};"); session.execute("USE " + keyspace + ";"); - } // else keyspace already exists + } else {// else keyspace already exists + session = cluster.connect(keyspace); + } } } } + + @After + public void after() { + if (clear && connected()) { + EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); + } + } } diff --git a/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CreateTableCqlGeneratorIntegrationTests.java b/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CreateTableCqlGeneratorIntegrationTests.java index be7b762d9..82872f163 100644 --- a/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CreateTableCqlGeneratorIntegrationTests.java +++ b/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CreateTableCqlGeneratorIntegrationTests.java @@ -3,6 +3,7 @@ package org.springframework.cassandra.test.integration.core.cql.generator; import static org.springframework.cassandra.test.integration.core.cql.generator.CqlTableSpecificationAssertions.assertTable; import org.junit.Test; +import org.springframework.cassandra.test.integration.AbstractEmbeddedCassandraIntegrationTest; import org.springframework.cassandra.test.unit.core.cql.generator.CreateTableCqlGeneratorTests.BasicTest; import org.springframework.cassandra.test.unit.core.cql.generator.CreateTableCqlGeneratorTests.CompositePartitionKeyTest; import org.springframework.cassandra.test.unit.core.cql.generator.CreateTableCqlGeneratorTests.CreateTableTest; diff --git a/src/test/java/org/springframework/cassandra/test/integration/core/template/CassandraOperationsTest.java b/src/test/java/org/springframework/cassandra/test/integration/core/template/CassandraOperationsTest.java new file mode 100644 index 000000000..246d628cb --- /dev/null +++ b/src/test/java/org/springframework/cassandra/test/integration/core/template/CassandraOperationsTest.java @@ -0,0 +1,275 @@ +/* + * 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.test.integration.core.template; + +import static org.junit.Assert.assertNotNull; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import junit.framework.Assert; + +import org.cassandraunit.CassandraCQLUnit; +import org.cassandraunit.dataset.cql.ClassPathCQLDataSet; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cassandra.core.CassandraOperations; +import org.springframework.cassandra.core.CassandraTemplate; +import org.springframework.cassandra.core.HostMapper; +import org.springframework.cassandra.core.PreparedStatementBinder; +import org.springframework.cassandra.core.ResultSetExtractor; +import org.springframework.cassandra.core.RingMember; +import org.springframework.cassandra.core.RowIterator; +import org.springframework.cassandra.test.integration.AbstractEmbeddedCassandraIntegrationTest; +import org.springframework.dao.DataAccessException; +import org.springframework.data.cassandra.test.integration.table.Book; + +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.exceptions.DriverException; + +/** + * Unit Tests for CassandraTemplate + * + * @author David Webb + * + */ +public class CassandraOperationsTest extends AbstractEmbeddedCassandraIntegrationTest { + + private CassandraOperations cassandraTemplate; + + private static Logger log = LoggerFactory.getLogger(CassandraOperationsTest.class); + + /* + * Objects used for test data + */ + final Object[] o1 = new Object[] { "1234", "Moby Dick", "Herman Manville", new Integer(456) }; + final Object[] o2 = new Object[] { "2345", "War and Peace", "Russian Dude", new Integer(456) }; + final Object[] o3 = new Object[] { "3456", "Jane Ayre", "Charlotte", new Integer(456) }; + + /** + * This loads any test specific Cassandra objects + */ + @Rule + public CassandraCQLUnit cassandraCQLUnit = new CassandraCQLUnit(new ClassPathCQLDataSet( + "cassandraOperationsTest-cql-dataload.cql", this.keyspace), CASSANDRA_CONFIG, CASSANDRA_HOST, + CASSANDRA_NATIVE_PORT); + + @Before + public void setupTemplate() { + cassandraTemplate = new CassandraTemplate(session); + } + + @Test + public void ringTest() { + + List ring = cassandraTemplate.describeRing(); + + /* + * There must be 1 node in the cluster if the embedded server is + * running. + */ + assertNotNull(ring); + + for (RingMember h : ring) { + log.info("ringTest Host -> " + h.address); + } + } + + @Test + public void hostMapperTest() { + + List ring = (List) cassandraTemplate.describeRing(new HostMapper() { + + @Override + public Collection mapHosts(Set host) throws DriverException { + + List list = new LinkedList(); + + for (Host h : host) { + MyHost mh = new MyHost(); + mh.someName = h.getAddress().getCanonicalHostName(); + list.add(mh); + } + + return list; + } + + }); + + assertNotNull(ring); + Assert.assertTrue(ring.size() > 0); + + for (MyHost h : ring) { + log.info("hostMapperTest Host -> " + h.someName); + } + + } + + @Test + public void ingestionTestListOfList() { + + String cql = "insert into book (isbn, title, author, pages) values (?, ?, ?, ?)"; + + List> values = new LinkedList>(); + + List l1 = new LinkedList(); + l1.add("1234"); + l1.add("Moby Dick"); + l1.add("Herman Manville"); + l1.add(new Integer(456)); + + values.add(l1); + + List l2 = new LinkedList(); + l2.add("2345"); + l2.add("War and Peace"); + l2.add("Russian Dude"); + l2.add(new Integer(456)); + + values.add(l2); + + // values.add(new Object[] { "3456", "Jane Ayre", "Charlotte", new Integer(456) }); + + cassandraTemplate.ingest(cql, values); + + // Assert that the rows were inserted into Cassandra + Book b1 = getBook("1234"); + Book b2 = getBook("2345"); + + Assert.assertEquals(b1.getIsbn(), l1.get(0)); + Assert.assertEquals(b2.getIsbn(), l2.get(0)); + } + + @Test + public void ingestionTestObjectArray() { + + String cql = "insert into book (isbn, title, author, pages) values (?, ?, ?, ?)"; + + Object[][] values = new Object[3][]; + values[0] = o1; + values[1] = o2; + values[2] = o3; + + cassandraTemplate.ingest(cql, values); + + // Assert that the rows were inserted into Cassandra + Book b1 = getBook("1234"); + Book b2 = getBook("2345"); + Book b3 = getBook("3456"); + + Assert.assertEquals(b1.getIsbn(), values[0][0]); + Assert.assertEquals(b2.getTitle(), values[1][1]); + Assert.assertEquals(b3.getAuthor(), values[2][2]); + } + + /** + * This is an implementation of RowIterator for the purposes of testing passing your own Impl to CassandraTemplate + * + * @author David Webb + */ + final class MyRowIterator implements RowIterator { + + private Object[][] values; + + public MyRowIterator(Object[][] values) { + this.values = values; + } + + int index = 0; + + /* (non-Javadoc) + * @see org.springframework.cassandra.core.RowIterator#next() + */ + @Override + public Object[] next() { + return values[index++]; + } + + /* (non-Javadoc) + * @see org.springframework.cassandra.core.RowIterator#hasNext() + */ + @Override + public boolean hasNext() { + return index < values.length; + } + + } + + @Test + public void ingestionTestRowIterator() { + + String cql = "insert into book (isbn, title, author, pages) values (?, ?, ?, ?)"; + + final Object[][] v = new Object[3][]; + v[0] = o1; + v[1] = o2; + v[2] = o3; + RowIterator ri = new MyRowIterator(v); + + cassandraTemplate.ingest(cql, ri); + + // Assert that the rows were inserted into Cassandra + Book b1 = getBook("1234"); + Book b2 = getBook("2345"); + Book b3 = getBook("3456"); + + Assert.assertEquals(b1.getIsbn(), o1[0]); + Assert.assertEquals(b2.getTitle(), o2[1]); + Assert.assertEquals(b3.getAuthor(), o3[2]); + } + + public Book getBook(final String isbn) { + + Book b = this.cassandraTemplate.query("select * from book where isbn = ?", new PreparedStatementBinder() { + + @Override + public BoundStatement bindValues(PreparedStatement ps) throws DriverException { + return ps.bind(isbn); + } + }, new ResultSetExtractor() { + + @Override + public Book extractData(ResultSet rs) throws DriverException, DataAccessException { + Book b = new Book(); + Row r = rs.one(); + b.setIsbn(r.getString("isbn")); + b.setTitle(r.getString("title")); + b.setAuthor(r.getString("author")); + b.setPages(r.getInt("pages")); + return b; + } + }); + + return b; + + } + + /** + * For testing a HostMapper Implementation + */ + public class MyHost { + public String someName; + } +} diff --git a/src/test/java/org/springframework/data/cassandra/test/integration/config/TestConfig.java b/src/test/java/org/springframework/data/cassandra/test/integration/config/TestConfig.java index e69e13cd2..415f5393e 100644 --- a/src/test/java/org/springframework/data/cassandra/test/integration/config/TestConfig.java +++ b/src/test/java/org/springframework/data/cassandra/test/integration/config/TestConfig.java @@ -22,12 +22,14 @@ import com.datastax.driver.core.Cluster.Builder; @Configuration public class TestConfig extends AbstractCassandraConfiguration { + public static final String keyspace = "test"; + /* (non-Javadoc) * @see org.springframework.data.cassandra.config.AbstractCassandraConfiguration#getKeyspaceName() */ @Override protected String getKeyspaceName() { - return "test"; + return keyspace; } /* (non-Javadoc) diff --git a/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraOperationsTest.java b/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraOperationsTest.java deleted file mode 100644 index 3945a1942..000000000 --- a/src/test/java/org/springframework/data/cassandra/test/integration/template/CassandraOperationsTest.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright 2011-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.cassandra.test.integration.template; - -import static org.junit.Assert.assertNotNull; - -import java.io.IOException; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -import junit.framework.Assert; - -import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.thrift.transport.TTransportException; -import org.cassandraunit.CassandraCQLUnit; -import org.cassandraunit.DataLoader; -import org.cassandraunit.dataset.cql.ClassPathCQLDataSet; -import org.cassandraunit.dataset.yaml.ClassPathYamlDataSet; -import org.cassandraunit.utils.EmbeddedCassandraServerHelper; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.cache.interceptor.DefaultKeyGenerator; -import org.springframework.cassandra.core.CachedPreparedStatementCreator; -import org.springframework.cassandra.core.CassandraOperations; -import org.springframework.cassandra.core.CqlParameter; -import org.springframework.cassandra.core.CqlParameterValue; -import org.springframework.cassandra.core.HostMapper; -import org.springframework.cassandra.core.PreparedStatementBinder; -import org.springframework.cassandra.core.PreparedStatementCreatorFactory; -import org.springframework.cassandra.core.ResultSetExtractor; -import org.springframework.cassandra.core.RingMember; -import org.springframework.dao.DataAccessException; -import org.springframework.data.cassandra.test.integration.config.TestConfig; -import org.springframework.data.cassandra.test.integration.table.Book; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.support.AnnotationConfigContextLoader; - -import com.datastax.driver.core.BoundStatement; -import com.datastax.driver.core.DataType; -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.exceptions.DriverException; - -/** - * Unit Tests for CassandraTemplate - * - * @author David Webb - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { TestConfig.class }, loader = AnnotationConfigContextLoader.class) -public class CassandraOperationsTest { - - /** - * @author David Webb - * - */ - public class MyHost { - - public String someName; - - } - - @Autowired - private CassandraOperations cassandraTemplate; - - private static Logger log = LoggerFactory.getLogger(CassandraOperationsTest.class); - - private final static String CASSANDRA_CONFIG = "cassandra.yaml"; - private final static String KEYSPACE_NAME = "test"; - private final static String CASSANDRA_HOST = "localhost"; - private final static int CASSANDRA_NATIVE_PORT = 9042; - private final static int CASSANDRA_THRIFT_PORT = 9160; - - @Rule - public CassandraCQLUnit cassandraCQLUnit = new CassandraCQLUnit(new ClassPathCQLDataSet( - "cassandraOperationsTest-cql-dataload.cql", KEYSPACE_NAME), CASSANDRA_CONFIG, CASSANDRA_HOST, - CASSANDRA_NATIVE_PORT); - - @BeforeClass - public static void startCassandra() throws IOException, TTransportException, ConfigurationException, - InterruptedException { - - EmbeddedCassandraServerHelper.startEmbeddedCassandra(CASSANDRA_CONFIG); - - /* - * Load data file to creat the test keyspace before we init the template - */ - DataLoader dataLoader = new DataLoader("Test Cluster", CASSANDRA_HOST + ":" + CASSANDRA_THRIFT_PORT); - dataLoader.load(new ClassPathYamlDataSet("cassandra-keyspace.yaml")); - } - - @Test - public void ringTest() { - - List ring = cassandraTemplate.describeRing(); - - /* - * There must be 1 node in the cluster if the embedded server is - * running. - */ - assertNotNull(ring); - - for (RingMember h : ring) { - log.info("ringTest Host -> " + h.address); - } - } - - @Test - public void hostMapperTest() { - - List ring = (List) cassandraTemplate.describeRing(new HostMapper() { - - @Override - public Collection mapHosts(Set host) throws DriverException { - - List list = new LinkedList(); - - for (Host h : host) { - MyHost mh = new MyHost(); - mh.someName = h.getAddress().getCanonicalHostName(); - list.add(mh); - } - - return list; - } - - }); - - assertNotNull(ring); - Assert.assertTrue(ring.size() > 0); - - for (MyHost h : ring) { - log.info("hostMapperTest Host -> " + h.someName); - } - - } - - @Test - public void preparedStatementFactoryTest() { - - String cql = "select * from book where isbn = ?"; - - List parameters = new LinkedList(); - parameters.add(new CqlParameter("isbn", DataType.text())); - - PreparedStatementCreatorFactory factory = new PreparedStatementCreatorFactory(cql, parameters); - - List values = new LinkedList(); - values.add(new CqlParameterValue(DataType.text(), "999999999")); - - Book b = cassandraTemplate.query(factory.newPreparedStatementCreator(values), - factory.newPreparedStatementBinder(values), new ResultSetExtractor() { - - @Override - public Book extractData(ResultSet rs) throws DriverException, DataAccessException { - Row r = rs.one(); - Book b = new Book(); - b.setIsbn(r.getString("isbn")); - b.setTitle(r.getString("title")); - b.setAuthor(r.getString("author")); - b.setPages(r.getInt("pages")); - return b; - } - }); - - log.info(b.toString()); - - } - - // @Test - public void cachedPreparedStatementTest() { - - log.info(echoString("Hello")); - log.info(echoString("Hello")); - - String cql = "select * from book where isbn = ?"; - - CachedPreparedStatementCreator cpsc = new CachedPreparedStatementCreator(cql); - - Book b = cassandraTemplate.query(cpsc, new PreparedStatementBinder() { - - @Override - public BoundStatement bindValues(PreparedStatement ps) throws DriverException { - return ps.bind("999999999"); - } - }, new ResultSetExtractor() { - - @Override - public Book extractData(ResultSet rs) throws DriverException, DataAccessException { - Row r = rs.one(); - Book b = new Book(); - b.setIsbn(r.getString("isbn")); - b.setTitle(r.getString("title")); - b.setAuthor(r.getString("author")); - b.setPages(r.getInt("pages")); - return b; - } - }); - - assertNotNull(b); - - log.info(b.toString()); - - try { - DefaultKeyGenerator generator = new DefaultKeyGenerator(); - - // TODO Why does method have to be public to work? Options? - Object cacheKey = generator.generate(CachedPreparedStatementCreator.class, - CachedPreparedStatementCreator.class.getMethod("getCachedPreparedStatement", Session.class, String.class), - cassandraTemplate.getSession(), cql); - - log.info("cacheKey -> " + cacheKey); - - // ConcurrentMapCache cache = (ConcurrentMapCache) cacheManager.getCache("sdc-pstmts"); - // ConcurrentMap cacheMap = cache.getNativeCache(); - // assertNotNull(cacheMap); - // log.info("CacheMap.size() -> " + cacheMap.size()); - // ValueWrapper vw = cache.get(cacheKey); - // PreparedStatement pstmt = (PreparedStatement) vw.get(); - // assertNotNull(pstmt); - // log.info(pstmt.getQueryString()); - // assertEquals(pstmt.getQueryString(), cql); - } catch (NoSuchMethodException e) { - log.error("Failed to find method", e); - } - - CachedPreparedStatementCreator cpsc2 = new CachedPreparedStatementCreator(cql); - - Book b2 = cassandraTemplate.query(cpsc2, new PreparedStatementBinder() { - - @Override - public BoundStatement bindValues(PreparedStatement ps) throws DriverException { - return ps.bind("999999999"); - } - }, new ResultSetExtractor() { - - @Override - public Book extractData(ResultSet rs) throws DriverException, DataAccessException { - Row r = rs.one(); - Book b = new Book(); - b.setIsbn(r.getString("isbn")); - b.setTitle(r.getString("title")); - b.setAuthor(r.getString("author")); - b.setPages(r.getInt("pages")); - return b; - } - }); - - assertNotNull(b2); - - log.info(b2.toString()); - - } - - @Cacheable("sdc-pstmts") - public String echoString(String s) { - log.info("In EchoString"); - return s; - } - - @After - public void clearCassandra() { - EmbeddedCassandraServerHelper.cleanEmbeddedCassandra(); - - } - - @AfterClass - public static void stopCassandra() { - // EmbeddedCassandraServerHelper.stopEmbeddedCassandra(); - } -}