DATACASS-287 - Polishing.
Move test listeners into a common support package. Hide constructors and introduce factory methods. Encapsulate fields. Add volatile modifier to fields to prevent visibility issues. Enhance JavaDoc on CassandraOperations.
This commit is contained in:
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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.support;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Convenient listener base class that includes a {@link CountDownLatch} in order to test asynchronous behavior.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public class TestListener {
|
||||
|
||||
protected CountDownLatch latch;
|
||||
|
||||
public TestListener() {
|
||||
this(1);
|
||||
}
|
||||
|
||||
public TestListener(int latchCount) {
|
||||
latch = new CountDownLatch(latchCount);
|
||||
}
|
||||
|
||||
public void await() throws InterruptedException {
|
||||
latch.await();
|
||||
}
|
||||
|
||||
public void await(long ms) throws InterruptedException {
|
||||
latch.await(ms, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void countDown() {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
package org.springframework.cassandra.test.integration.core;
|
||||
|
||||
import org.springframework.cassandra.core.AsynchronousQueryListener;
|
||||
import org.springframework.cassandra.support.TestListener;
|
||||
import org.springframework.cassandra.test.integration.support.CallbackSynchronizationSupport;
|
||||
|
||||
import com.datastax.driver.core.ResultSetFuture;
|
||||
import com.datastax.driver.core.Row;
|
||||
@@ -26,8 +26,9 @@ import com.datastax.driver.core.Row;
|
||||
*
|
||||
* @author David Webb
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class BookListener extends TestListener implements AsynchronousQueryListener {
|
||||
public class BookListener extends CallbackSynchronizationSupport implements AsynchronousQueryListener {
|
||||
|
||||
private Book book;
|
||||
private boolean done;
|
||||
|
||||
@@ -41,6 +41,10 @@ import org.springframework.cassandra.core.QueryOptions;
|
||||
import org.springframework.cassandra.core.RetryPolicy;
|
||||
import org.springframework.cassandra.support.exception.CassandraConnectionFailureException;
|
||||
import org.springframework.cassandra.test.integration.AbstractKeyspaceCreatingIntegrationTest;
|
||||
import org.springframework.cassandra.test.integration.support.QueryListener;
|
||||
import org.springframework.cassandra.test.integration.support.ListOfMapListener;
|
||||
import org.springframework.cassandra.test.integration.support.MapListener;
|
||||
import org.springframework.cassandra.test.integration.support.ObjectListener;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -135,7 +139,7 @@ public class AsynchronousCqlOperationsIntegrationTests extends AbstractKeyspaceC
|
||||
|
||||
/**
|
||||
* Tests that test {@link AsynchronousQueryListener} should create an anonymous subclass of this class then call
|
||||
* either {@link #test()} or {@link #test(int)}
|
||||
* {@link #test()}.
|
||||
*/
|
||||
abstract class AsynchronousQueryListenerTestTemplate {
|
||||
|
||||
@@ -143,22 +147,22 @@ public class AsynchronousCqlOperationsIntegrationTests extends AbstractKeyspaceC
|
||||
* Subclass must perform the asynchronous query using the given data and listener and set <code>this.expected</code>
|
||||
* to the appropriate value before returning.
|
||||
*/
|
||||
abstract void doAsyncQuery(Book b, BasicListener listener);
|
||||
abstract void doAsyncQuery(Book b, QueryListener listener);
|
||||
|
||||
void test() throws InterruptedException {
|
||||
Book expected = insert(1)[0];
|
||||
BasicListener listener = new BasicListener();
|
||||
QueryListener listener = QueryListener.create();
|
||||
doAsyncQuery(expected, listener);
|
||||
listener.await();
|
||||
Row r = cqlOperations.getResultSetUninterruptibly(listener.rsf).one();
|
||||
Row r = cqlOperations.getResultSetUninterruptibly(listener.getResultSetFuture()).one();
|
||||
Book actual = new Book(r.getString(0), r.getString(1));
|
||||
assertBook(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that test {@link QueryForObjectListener} should create an anonymous subclass of this class then call either
|
||||
* {@link #test()} or {@link #test(int)}
|
||||
* Tests that test {@link QueryForObjectListener} should create an anonymous subclass of this class then call
|
||||
* {@link #test()}
|
||||
*/
|
||||
abstract class QueryForObjectListenerTestTemplate<T> {
|
||||
|
||||
@@ -172,19 +176,19 @@ public class AsynchronousCqlOperationsIntegrationTests extends AbstractKeyspaceC
|
||||
|
||||
void test() throws Exception {
|
||||
Book book = insert(1)[0];
|
||||
ObjectListener<T> listener = new ObjectListener<T>();
|
||||
ObjectListener<T> listener = ObjectListener.create();
|
||||
doAsyncQuery(book, listener);
|
||||
listener.await();
|
||||
if (listener.exception != null) {
|
||||
throw listener.exception;
|
||||
if (listener.getException() != null) {
|
||||
throw listener.getException();
|
||||
}
|
||||
assertEquals(expected, listener.result);
|
||||
assertEquals(expected, listener.getResult());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that test {@link QueryForMapListener} should create an anonymous subclass of this class then call either
|
||||
* {@link #test()} or {@link #test(int)}
|
||||
* Tests that test {@link QueryForMapListener} should create an anonymous subclass of this class then call
|
||||
* {@link #test()}
|
||||
*/
|
||||
abstract class QueryForMapListenerTestTemplate {
|
||||
|
||||
@@ -198,19 +202,18 @@ public class AsynchronousCqlOperationsIntegrationTests extends AbstractKeyspaceC
|
||||
|
||||
void test() throws Exception {
|
||||
Book book = insert(1)[0];
|
||||
MapListener listener = new MapListener();
|
||||
MapListener listener = MapListener.create();
|
||||
doAsyncQuery(book, listener);
|
||||
listener.await();
|
||||
if (listener.exception != null) {
|
||||
throw listener.exception;
|
||||
if (listener.getException() != null) {
|
||||
throw listener.getException();
|
||||
}
|
||||
assertMapEquals(expected, listener.result);
|
||||
assertMapEquals(expected, listener.getResult());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that test {@link QueryForMapListener} should create an anonymous subclass of this class then call either
|
||||
* {@link #test()} or {@link #test(int)}
|
||||
* Tests that test {@link QueryForMapListener} should create an anonymous subclass of this class then call or {@link #test(int)}
|
||||
*/
|
||||
abstract class QueryForListListenerTestTemplate {
|
||||
|
||||
@@ -224,19 +227,19 @@ public class AsynchronousCqlOperationsIntegrationTests extends AbstractKeyspaceC
|
||||
|
||||
void test(int n) throws Exception {
|
||||
Book[] books = insert(n);
|
||||
ListOfMapListener listener = new ListOfMapListener();
|
||||
ListOfMapListener listener = ListOfMapListener.create();
|
||||
Arrays.sort(books, BOOK_COMPARATOR);
|
||||
doAsyncQuery(books, listener);
|
||||
listener.await();
|
||||
if (listener.exception != null) {
|
||||
throw listener.exception;
|
||||
if (listener.getException() != null) {
|
||||
throw listener.getException();
|
||||
}
|
||||
|
||||
// sort results the same way as the books array above
|
||||
Collections.sort(listener.result, MAP_WITH_ISBN_COMPARATOR);
|
||||
Collections.sort(listener.getResult(), MAP_WITH_ISBN_COMPARATOR);
|
||||
|
||||
for (int i = 0; i < expected.size(); i++) {
|
||||
assertMapEquals(expected.get(i), listener.result.get(i));
|
||||
assertMapEquals(expected.get(i), listener.getResult().get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,7 +248,7 @@ public class AsynchronousCqlOperationsIntegrationTests extends AbstractKeyspaceC
|
||||
public void testString_AsynchronousQueryListener_Cancelled() throws InterruptedException {
|
||||
new AsynchronousQueryListenerTestTemplate() {
|
||||
@Override
|
||||
void doAsyncQuery(Book b, BasicListener listener) {
|
||||
void doAsyncQuery(Book b, QueryListener listener) {
|
||||
Cancellable qc = cqlOperations.queryAsynchronously(cql(b), listener);
|
||||
qc.cancel();
|
||||
}
|
||||
@@ -256,7 +259,7 @@ public class AsynchronousCqlOperationsIntegrationTests extends AbstractKeyspaceC
|
||||
public void testString_AsynchronousQueryListener() throws InterruptedException {
|
||||
new AsynchronousQueryListenerTestTemplate() {
|
||||
@Override
|
||||
void doAsyncQuery(Book b, BasicListener listener) {
|
||||
void doAsyncQuery(Book b, QueryListener listener) {
|
||||
cqlOperations.queryAsynchronously(cql(b), listener);
|
||||
}
|
||||
}.test();
|
||||
@@ -265,7 +268,7 @@ public class AsynchronousCqlOperationsIntegrationTests extends AbstractKeyspaceC
|
||||
public void testString_AsynchronousQueryListener_QueryOptions(final ConsistencyLevel cl) throws InterruptedException {
|
||||
new AsynchronousQueryListenerTestTemplate() {
|
||||
@Override
|
||||
void doAsyncQuery(Book b, BasicListener listener) {
|
||||
void doAsyncQuery(Book b, QueryListener listener) {
|
||||
cqlOperations.queryAsynchronously(cql(b), listener, new QueryOptions(cl, RetryPolicy.LOGGING));
|
||||
}
|
||||
}.test();
|
||||
@@ -285,7 +288,7 @@ public class AsynchronousCqlOperationsIntegrationTests extends AbstractKeyspaceC
|
||||
public void testSelect_AsynchronousQueryListener() throws InterruptedException {
|
||||
new AsynchronousQueryListenerTestTemplate() {
|
||||
@Override
|
||||
void doAsyncQuery(Book b, BasicListener listener) {
|
||||
void doAsyncQuery(Book b, QueryListener listener) {
|
||||
cqlOperations.queryAsynchronously(cql(b), listener);
|
||||
}
|
||||
}.test();
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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.async;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cassandra.core.QueryForListOfMapListener;
|
||||
|
||||
/**
|
||||
* @author Matthew T. Adams
|
||||
*/
|
||||
public class ListOfMapListener extends ListListener<Map<String, Object>> implements QueryForListOfMapListener {}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2016 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.support;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Convenient listener base class that includes a {@link CountDownLatch} in order to test asynchronous behavior. This
|
||||
* class can be extended
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract class CallbackSynchronizationSupport {
|
||||
|
||||
private final CountDownLatch latch;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CallbackSynchronizationSupport}
|
||||
*/
|
||||
protected CallbackSynchronizationSupport() {
|
||||
this(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link CallbackSynchronizationSupport} for a given {@code latchCount} of callbacks.
|
||||
*
|
||||
* @param latchCount {@link CallbackSynchronizationSupport} for a given {@code latchCount} of callbacks
|
||||
*/
|
||||
protected CallbackSynchronizationSupport(int latchCount) {
|
||||
latch = new CountDownLatch(latchCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Await results without a timeout.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public final void await() throws InterruptedException {
|
||||
latch.await();
|
||||
}
|
||||
|
||||
/**
|
||||
* Await the results with a timeout.
|
||||
*
|
||||
* @param timeout must be greater or equal to 0
|
||||
* @param timeUnit must not be {@literal null}.
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public final void await(long timeout, TimeUnit timeUnit) throws InterruptedException {
|
||||
|
||||
Assert.isTrue(timeout >= 0, "Timeout must be greater or equal to 0");
|
||||
Assert.notNull(timeUnit, "TimeUnit must not be null");
|
||||
|
||||
latch.await(timeout, timeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate an incoming event and count down the latch by {@literal 1}.
|
||||
*/
|
||||
protected final void countDown() {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
@@ -13,31 +13,56 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cassandra.test.integration.core.async;
|
||||
package org.springframework.cassandra.test.integration.support;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cassandra.core.QueryForListListener;
|
||||
import org.springframework.cassandra.support.TestListener;
|
||||
|
||||
/**
|
||||
* {@link QueryForListListener} suitable for tests.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author David Webb
|
||||
*/
|
||||
public class ListListener<T> extends TestListener implements QueryForListListener<T> {
|
||||
public class ListListener<T> extends CallbackSynchronizationSupport implements QueryForListListener<T> {
|
||||
|
||||
Exception exception;
|
||||
List<T> result;
|
||||
private volatile Exception exception;
|
||||
private volatile List<T> result;
|
||||
|
||||
/**
|
||||
* Allow instances only using {@link #create()}
|
||||
*/
|
||||
private ListListener() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new {@link QueryForListListener}.
|
||||
*/
|
||||
public static <T> ListListener<T> create() {
|
||||
return new ListListener<T>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueryComplete(List<T> results) {
|
||||
|
||||
this.result = results;
|
||||
countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Exception x) {
|
||||
|
||||
this.exception = x;
|
||||
countDown();
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public List<T> getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2016 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.support;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cassandra.core.QueryForListListener;
|
||||
import org.springframework.cassandra.core.QueryForListOfMapListener;
|
||||
|
||||
/**
|
||||
* {@link QueryForListListener} suitable for tests.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author David Webb
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class ListOfMapListener extends CallbackSynchronizationSupport implements QueryForListOfMapListener {
|
||||
|
||||
private volatile Exception exception;
|
||||
private volatile List<Map<String, Object>> result;
|
||||
|
||||
/**
|
||||
* Allow instances only using {@link #create()}
|
||||
*/
|
||||
private ListOfMapListener() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new {@link QueryForListListener}.
|
||||
*/
|
||||
public static ListOfMapListener create() {
|
||||
return new ListOfMapListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueryComplete(List<Map<String, Object>> results) {
|
||||
|
||||
this.result = results;
|
||||
countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Exception x) {
|
||||
|
||||
this.exception = x;
|
||||
countDown();
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -13,30 +13,56 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cassandra.test.integration.core.async;
|
||||
package org.springframework.cassandra.test.integration.support;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cassandra.core.QueryForMapListener;
|
||||
import org.springframework.cassandra.support.TestListener;
|
||||
|
||||
/**
|
||||
* {@link QueryForMapListener} suitable for tests.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class MapListener extends TestListener implements QueryForMapListener {
|
||||
public class MapListener extends CallbackSynchronizationSupport implements QueryForMapListener {
|
||||
|
||||
Map<String, Object> result;
|
||||
Exception exception;
|
||||
private volatile Map<String, Object> result;
|
||||
private volatile Exception exception;
|
||||
|
||||
/**
|
||||
* Allow instances only using {@link #create()}
|
||||
*/
|
||||
private MapListener(){
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new {@link ObjectListener}.
|
||||
*/
|
||||
public static MapListener create() {
|
||||
return new MapListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueryComplete(Map<String, Object> results) {
|
||||
|
||||
this.result = results;
|
||||
countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Exception x) {
|
||||
|
||||
this.exception = x;
|
||||
countDown();
|
||||
}
|
||||
|
||||
public Map<String, Object> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
@@ -13,19 +13,35 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cassandra.test.integration.core.async;
|
||||
package org.springframework.cassandra.test.integration.support;
|
||||
|
||||
import org.springframework.cassandra.core.QueryForObjectListener;
|
||||
import org.springframework.cassandra.support.TestListener;
|
||||
|
||||
/**
|
||||
* {@link QueryForObjectListener} suitable for tests.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author David Webb
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class ObjectListener<T> extends TestListener implements QueryForObjectListener<T> {
|
||||
public class ObjectListener<T> extends CallbackSynchronizationSupport implements QueryForObjectListener<T> {
|
||||
|
||||
public volatile T result;
|
||||
public volatile Exception exception;
|
||||
private volatile T result;
|
||||
private volatile Exception exception;
|
||||
|
||||
/**
|
||||
* Allow instances only using {@link #create()}
|
||||
*/
|
||||
private ObjectListener(){
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new {@link ObjectListener}.
|
||||
*/
|
||||
public static <T> ObjectListener<T> create() {
|
||||
return new ObjectListener<T>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueryComplete(T result) {
|
||||
@@ -40,4 +56,12 @@ public class ObjectListener<T> extends TestListener implements QueryForObjectLis
|
||||
this.exception = x;
|
||||
countDown();
|
||||
}
|
||||
|
||||
public T getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
@@ -13,24 +13,45 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cassandra.test.integration.core.async;
|
||||
package org.springframework.cassandra.test.integration.support;
|
||||
|
||||
import org.springframework.cassandra.core.AsynchronousQueryListener;
|
||||
import org.springframework.cassandra.support.TestListener;
|
||||
|
||||
import com.datastax.driver.core.ResultSetFuture;
|
||||
|
||||
/**
|
||||
* {@link AsynchronousQueryListener} suitable for usage in tests.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author David Webb
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class BasicListener extends TestListener implements AsynchronousQueryListener {
|
||||
public class QueryListener extends CallbackSynchronizationSupport implements AsynchronousQueryListener {
|
||||
|
||||
ResultSetFuture rsf;
|
||||
private volatile ResultSetFuture rsf;
|
||||
|
||||
/**
|
||||
* Allow instances only using {@link #create()}
|
||||
*/
|
||||
private QueryListener() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new {@link QueryListener}.
|
||||
*/
|
||||
public static QueryListener create() {
|
||||
return new QueryListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueryComplete(ResultSetFuture rsf) {
|
||||
this.rsf = rsf;
|
||||
public void onQueryComplete(ResultSetFuture resultSetFuture) {
|
||||
|
||||
this.rsf = resultSetFuture;
|
||||
countDown();
|
||||
}
|
||||
|
||||
public ResultSetFuture getResultSetFuture() {
|
||||
return rsf;
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,12 @@ import com.datastax.driver.core.querybuilder.Select;
|
||||
* @author Alex Shvid
|
||||
* @author David Webb
|
||||
* @author Matthew Adams
|
||||
* @author Mark Paluch
|
||||
* @see CqlOperations
|
||||
* @see Select
|
||||
* @see WriteListener
|
||||
* @see DeletionListener
|
||||
* @see QueryForObjectListener
|
||||
*/
|
||||
public interface CassandraOperations extends CqlOperations {
|
||||
|
||||
@@ -41,39 +47,72 @@ public interface CassandraOperations extends CqlOperations {
|
||||
* The table name used for the specified class by this template.
|
||||
*
|
||||
* @param entityClass must not be {@literal null}.
|
||||
* @return
|
||||
* @return the {@link CqlIdentifier}
|
||||
*/
|
||||
CqlIdentifier getTableName(Class<?> entityClass);
|
||||
|
||||
/**
|
||||
* Execute query and convert ResultSet to the list of entities
|
||||
* Execute query and convert ResultSet to the list of entities.
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param cql must not be {@literal null}.
|
||||
* @param type must not be {@literal null}, mapped entity type.
|
||||
* @return
|
||||
* @return the converted results
|
||||
*/
|
||||
<T> List<T> select(String cql, Class<T> type);
|
||||
|
||||
/**
|
||||
* Execute the Select Query and convert to the list of entities
|
||||
* Execute the Select Query and convert to the list of entities.
|
||||
*
|
||||
* @param select must not be {@literal null}.
|
||||
* @param type must not be {@literal null}, mapped entity type.
|
||||
* @return
|
||||
* @return the converted results
|
||||
*/
|
||||
<T> List<T> select(Select select, Class<T> type);
|
||||
|
||||
/**
|
||||
* Select objects for the given {@code type} and {@code ids}.
|
||||
*
|
||||
* @param type must not be {@literal null}, mapped entity type.
|
||||
* @param ids must not be {@literal null}.
|
||||
* @return the converted results
|
||||
*/
|
||||
<T> List<T> selectBySimpleIds(Class<T> type, Iterable<?> ids);
|
||||
|
||||
/**
|
||||
* @deprecated Calling this method could result in {@link OutOfMemoryError}, as this is a brute force selection.
|
||||
* @param type The type of entity to select.
|
||||
* @return A list of all entities of type <code>T</code>.
|
||||
*/
|
||||
@Deprecated
|
||||
<T> List<T> selectAll(Class<T> type);
|
||||
|
||||
/**
|
||||
* Execute the Select by {@code id} for the given {@code type}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param id must not be {@literal null}.
|
||||
* @return the converted object or {@literal null}.
|
||||
*/
|
||||
<T> T selectOneById(Class<T> type, Object id);
|
||||
|
||||
/**
|
||||
* Execute CQL and convert ResultSet to the entity
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param cql must not be {@literal null}.
|
||||
* @param type must not be {@literal null}, mapped entity type.
|
||||
* @return
|
||||
* @return the converted object or {@literal null}.
|
||||
*/
|
||||
<T> T selectOne(String cql, Class<T> type);
|
||||
|
||||
/**
|
||||
* Execute Select query and convert ResultSet to the entity
|
||||
*
|
||||
* @param select must not be {@literal null}.
|
||||
* @param type must not be {@literal null}, mapped entity type.
|
||||
* @return the converted object or {@literal null}.
|
||||
*/
|
||||
<T> T selectOne(Select select, Class<T> type);
|
||||
|
||||
/**
|
||||
* Executes the {@link Select} query asynchronously.
|
||||
*
|
||||
@@ -86,7 +125,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Executes the string CQL query asynchronously.
|
||||
*
|
||||
* @param select The string query CQL to execute.
|
||||
* @param cql The string query CQL to execute.
|
||||
* @param type The type of entity to retrieve.
|
||||
* @return A {@link Cancellable} that can be used to cancel the query.
|
||||
*/
|
||||
@@ -106,7 +145,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Executes the string CQL query asynchronously.
|
||||
*
|
||||
* @param select The string query CQL to execute.
|
||||
* @param cql The string query CQL to execute.
|
||||
* @param type The type of entity to retrieve.
|
||||
* @param options The {@link QueryOptions} to use.
|
||||
* @return A {@link Cancellable} that can be used to cancel the query.
|
||||
@@ -115,16 +154,20 @@ public interface CassandraOperations extends CqlOperations {
|
||||
QueryOptions options);
|
||||
|
||||
/**
|
||||
* Execute Select query and convert ResultSet to the entity
|
||||
* Determine whether the row {@code type} with the given {@code id} exists.
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param type must not be {@literal null}, mapped entity type.
|
||||
* @return
|
||||
* @param type must not be {@literal null}.
|
||||
* @param id must not be {@literal null}.
|
||||
* @return true, if the object exists
|
||||
*/
|
||||
<T> T selectOne(Select select, Class<T> type);
|
||||
|
||||
boolean exists(Class<?> type, Object id);
|
||||
|
||||
/**
|
||||
* Returns the number of rows for the given {@code type} by querying the table of the given entity class.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @return number of rows
|
||||
*/
|
||||
long count(Class<?> type);
|
||||
|
||||
/**
|
||||
@@ -207,7 +250,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Inserts the given entities asynchronously in a batch.
|
||||
*
|
||||
* @param entity The entities to insert
|
||||
* @param entities The entities to insert
|
||||
* @return The entities given
|
||||
* @see #insertAsynchronously(List, WriteListener)
|
||||
* @deprecated This method does not allow for query cancellation or notification of completion. Favor
|
||||
@@ -219,7 +262,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Inserts the given entities asynchronously in a batch.
|
||||
*
|
||||
* @param entity The entities to insert
|
||||
* @param entities The entities to insert
|
||||
* @return The entities given
|
||||
* @see #insertAsynchronously(List, WriteListener, WriteOptions)
|
||||
* @deprecated This method does not allow for query cancellation or notification of completion. Favor
|
||||
@@ -231,7 +274,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Inserts the given entities asynchronously in a batch.
|
||||
*
|
||||
* @param entity The entities to insert
|
||||
* @param entities The entities to insert
|
||||
* @param listener The listener to receive notification of completion
|
||||
* @return A {@link Cancellable} enabling the cancellation of the operation
|
||||
*/
|
||||
@@ -240,7 +283,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Inserts the given entities asynchronously in a batch.
|
||||
*
|
||||
* @param entity The entities to insert
|
||||
* @param entities The entities to insert
|
||||
* @param listener The listener to receive notification of completion
|
||||
* @param options The {@link WriteOptions} to use
|
||||
* @return A {@link Cancellable} enabling the cancellation of the operation
|
||||
@@ -327,7 +370,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Updates the given entities asynchronously in a batch.
|
||||
*
|
||||
* @param entity The entities to update
|
||||
* @param entities The entities to update
|
||||
* @return The entities given
|
||||
* @see #updateAsynchronously(List, WriteListener)
|
||||
* @deprecated This method does not allow for query cancellation or notification of completion. Favor
|
||||
@@ -339,7 +382,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Updates the given entities asynchronously in a batch.
|
||||
*
|
||||
* @param entity The entities to update
|
||||
* @param entities The entities to update
|
||||
* @return The entities given
|
||||
* @see #updateAsynchronously(List, WriteListener, WriteOptions)
|
||||
* @deprecated This method does not allow for query cancellation or notification of completion. Favor
|
||||
@@ -351,7 +394,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Updates the given entities asynchronously in a batch.
|
||||
*
|
||||
* @param entity The entities to update
|
||||
* @param entities The entities to update
|
||||
* @param listener The listener to receive notification of completion
|
||||
* @return A {@link Cancellable} enabling the cancellation of the operation
|
||||
*/
|
||||
@@ -360,7 +403,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Updates the given entities asynchronously in a batch.
|
||||
*
|
||||
* @param entity The entities to update
|
||||
* @param entities The entities to update
|
||||
* @param listener The listener to receive notification of completion
|
||||
* @param options The {@link WriteOptions} to use
|
||||
* @return A {@link Cancellable} enabling the cancellation of the operation
|
||||
@@ -370,24 +413,39 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Remove the given object from the table by id.
|
||||
*
|
||||
* @param object
|
||||
* @param type must not be {@literal null}.
|
||||
* @param id must not be {@literal null}.
|
||||
*/
|
||||
<T> void delete(T entity);
|
||||
|
||||
/**
|
||||
* @param entity
|
||||
* @param tableName
|
||||
* @param options
|
||||
*/
|
||||
<T> void delete(T entity, QueryOptions options);
|
||||
void deleteById(Class<?> type, Object id);
|
||||
|
||||
/**
|
||||
* Remove the given object from the table by id.
|
||||
*
|
||||
* @param object
|
||||
* @param entity must not be {@literal null}.
|
||||
*/
|
||||
<T> void delete(T entity);
|
||||
|
||||
/**
|
||||
* Remove the given object from the table by id.
|
||||
*
|
||||
* @param entity must not be {@literal null}.
|
||||
* @param options may be {@literal null}.
|
||||
*/
|
||||
<T> void delete(T entity, QueryOptions options);
|
||||
|
||||
/**
|
||||
* Remove the given objects from the table by id.
|
||||
*
|
||||
* @param entities must not be {@literal null}.
|
||||
*/
|
||||
<T> void delete(List<T> entities);
|
||||
|
||||
/**
|
||||
* Remove the given objects from the table by id.
|
||||
*
|
||||
* @param entities must not be {@literal null}.
|
||||
* @param options may be {@literal null}.
|
||||
*/
|
||||
<T> void delete(List<T> entities, QueryOptions options);
|
||||
|
||||
/**
|
||||
@@ -462,19 +520,7 @@ public interface CassandraOperations extends CqlOperations {
|
||||
/**
|
||||
* Returns the underlying {@link CassandraConverter}.
|
||||
*
|
||||
* @return
|
||||
* @return the underlying {@link CassandraConverter}.
|
||||
*/
|
||||
CassandraConverter getConverter();
|
||||
|
||||
void deleteById(Class<?> type, Object id);
|
||||
|
||||
<T> List<T> selectBySimpleIds(Class<T> type, Iterable<?> ids);
|
||||
|
||||
/**
|
||||
* @deprecated Calling this method could result in {@link OutOfMemoryError}, as this is a brute force selection.
|
||||
* @param type The type of entity to select.
|
||||
* @return A list of all entities of type <code>T</code>.
|
||||
*/
|
||||
@Deprecated
|
||||
<T> List<T> selectAll(Class<T> type);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -35,7 +38,7 @@ import org.springframework.cassandra.core.PrimaryKeyType;
|
||||
import org.springframework.cassandra.core.RetryPolicy;
|
||||
import org.springframework.cassandra.core.WriteOptions;
|
||||
import org.springframework.cassandra.support.exception.CassandraConnectionFailureException;
|
||||
import org.springframework.cassandra.test.integration.core.async.ObjectListener;
|
||||
import org.springframework.cassandra.test.integration.support.ObjectListener;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.cassandra.core.CassandraOperations;
|
||||
import org.springframework.data.cassandra.core.CassandraTemplate;
|
||||
@@ -54,6 +57,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
* Integration tests for asynchronous {@link CassandraTemplate} operations.
|
||||
*
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@@ -78,17 +82,17 @@ public class AsynchronousCassandraTemplateIntegrationTests extends AbstractSprin
|
||||
|
||||
public void insertAsynchronously(ConsistencyLevel cl) throws Exception {
|
||||
|
||||
Thing thing = Thing.random();
|
||||
ThingListener listener = new ThingListener();
|
||||
Person person = Person.random();
|
||||
PersonListener listener = new PersonListener();
|
||||
|
||||
cassandraOperations.insertAsynchronously(thing, listener, new WriteOptions(cl, RetryPolicy.LOGGING));
|
||||
cassandraOperations.insertAsynchronously(person, listener, new WriteOptions(cl, RetryPolicy.LOGGING));
|
||||
listener.await();
|
||||
|
||||
if (listener.exception != null) {
|
||||
throw listener.exception;
|
||||
}
|
||||
|
||||
assertEquals(thing, listener.entities.iterator().next());
|
||||
assertEquals(person, listener.entities.iterator().next());
|
||||
}
|
||||
|
||||
@Test(expected = CancellationException.class)
|
||||
@@ -103,15 +107,15 @@ public class AsynchronousCassandraTemplateIntegrationTests extends AbstractSprin
|
||||
|
||||
public void insertOrUpdateAsynchronouslyCancelled(boolean insert) throws Exception {
|
||||
|
||||
Thing thing = Thing.random();
|
||||
ThingListener listener = new ThingListener();
|
||||
Person person = Person.random();
|
||||
PersonListener listener = new PersonListener();
|
||||
|
||||
Cancellable cancellable;
|
||||
|
||||
if (insert) {
|
||||
cancellable = cassandraOperations.insertAsynchronously(thing, listener, null);
|
||||
cancellable = cassandraOperations.insertAsynchronously(person, listener, null);
|
||||
} else {
|
||||
cancellable = cassandraOperations.updateAsynchronously(thing, listener, null);
|
||||
cancellable = cassandraOperations.updateAsynchronously(person, listener, null);
|
||||
}
|
||||
cancellable.cancel();
|
||||
listener.await();
|
||||
@@ -140,19 +144,19 @@ public class AsynchronousCassandraTemplateIntegrationTests extends AbstractSprin
|
||||
|
||||
public void updateAsynchronously(ConsistencyLevel cl) throws Exception {
|
||||
|
||||
Thing thing = Thing.random();
|
||||
cassandraOperations.insert(thing);
|
||||
thing.number = Thing.random().number;
|
||||
Person person = Person.random();
|
||||
person.setFirstname("Homer");
|
||||
cassandraOperations.insert(person);
|
||||
|
||||
ThingListener listener = new ThingListener();
|
||||
cassandraOperations.updateAsynchronously(thing, listener, new WriteOptions(cl, RetryPolicy.LOGGING));
|
||||
PersonListener listener = new PersonListener();
|
||||
cassandraOperations.updateAsynchronously(person, listener, new WriteOptions(cl, RetryPolicy.LOGGING));
|
||||
|
||||
listener.await();
|
||||
if (listener.exception != null) {
|
||||
throw listener.exception;
|
||||
}
|
||||
|
||||
assertEquals(thing, listener.entities.iterator().next());
|
||||
assertEquals(person, listener.entities.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -167,26 +171,26 @@ public class AsynchronousCassandraTemplateIntegrationTests extends AbstractSprin
|
||||
|
||||
public void deleteAsynchronously(ConsistencyLevel cl) throws Exception {
|
||||
|
||||
Thing thing = Thing.random();
|
||||
Person person = Person.random();
|
||||
|
||||
cassandraOperations.insert(thing);
|
||||
cassandraOperations.insert(person);
|
||||
|
||||
ThingListener listener = new ThingListener();
|
||||
cassandraOperations.deleteAsynchronously(thing, listener, new WriteOptions(cl, RetryPolicy.LOGGING));
|
||||
PersonListener listener = new PersonListener();
|
||||
cassandraOperations.deleteAsynchronously(person, listener, new WriteOptions(cl, RetryPolicy.LOGGING));
|
||||
|
||||
listener.await();
|
||||
if (listener.exception != null) {
|
||||
throw listener.exception;
|
||||
}
|
||||
assertFalse(cassandraOperations.exists(Thing.class, id("stuff", thing.stuff)));
|
||||
assertFalse(cassandraOperations.exists(Person.class, id("id", person.id)));
|
||||
}
|
||||
|
||||
@Test(expected = CancellationException.class)
|
||||
public void deleteAsynchronouslyCancelled() throws Exception {
|
||||
|
||||
Thing thing = Thing.random();
|
||||
ThingListener listener = new ThingListener();
|
||||
cassandraOperations.deleteAsynchronously(thing, listener, null).cancel();
|
||||
Person person = Person.random();
|
||||
PersonListener listener = new PersonListener();
|
||||
cassandraOperations.deleteAsynchronously(person, listener, null).cancel();
|
||||
listener.await();
|
||||
|
||||
// if listener.success is true then the
|
||||
@@ -207,17 +211,17 @@ public class AsynchronousCassandraTemplateIntegrationTests extends AbstractSprin
|
||||
@Test(timeout = 10000)
|
||||
public void shouldSelectOneAsynchronously() throws Exception {
|
||||
|
||||
Thing thing = Thing.random();
|
||||
cassandraOperations.insert(thing);
|
||||
Person person = Person.random();
|
||||
cassandraOperations.insert(person);
|
||||
|
||||
ObjectListener<Thing> objectListener = new ObjectListener<Thing>();
|
||||
String cql = String.format("SELECT * from thing where stuff = '%s'", thing.stuff);
|
||||
ObjectListener<Person> objectListener = ObjectListener.create();
|
||||
String cql = String.format("SELECT * from person where id = '%s'", person.id);
|
||||
|
||||
cassandraOperations.selectOneAsynchronously(cql, Thing.class, objectListener);
|
||||
cassandraOperations.selectOneAsynchronously(cql, Person.class, objectListener);
|
||||
objectListener.await();
|
||||
|
||||
assertThat(objectListener.result, is(notNullValue()));
|
||||
assertThat(objectListener.result.stuff, is(equalTo(thing.stuff)));
|
||||
assertThat(objectListener.getResult(), is(notNullValue()));
|
||||
assertThat(objectListener.getResult().id, is(equalTo(person.id)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,85 +230,56 @@ public class AsynchronousCassandraTemplateIntegrationTests extends AbstractSprin
|
||||
@Test(timeout = 10000)
|
||||
public void shouldSelectOneAsynchronouslyIfObjectIsAbsent() throws Exception {
|
||||
|
||||
ObjectListener<Thing> objectListener = new ObjectListener<Thing>();
|
||||
String cql = String.format("SELECT * from thing where stuff = '%s'", UUID.randomUUID());
|
||||
ObjectListener<Person> objectListener = ObjectListener.create();
|
||||
String cql = String.format("SELECT * from person where id = '%s'", "unknown");
|
||||
|
||||
cassandraOperations.selectOneAsynchronously(cql, Thing.class, objectListener);
|
||||
cassandraOperations.selectOneAsynchronously(cql, Person.class, objectListener);
|
||||
objectListener.await();
|
||||
|
||||
assertThat(objectListener.result, is(nullValue()));
|
||||
assertThat(objectListener.getResult(), is(nullValue()));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class Config extends IntegrationTestConfig {}
|
||||
|
||||
@Table
|
||||
public static class Thing {
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class Person {
|
||||
|
||||
private static final Random RNG = new Random();
|
||||
|
||||
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) public String stuff;
|
||||
@Column public int number;
|
||||
|
||||
public Thing() {}
|
||||
|
||||
public Thing(String stuff, int number) {
|
||||
this.stuff = stuff;
|
||||
this.number = number;
|
||||
}
|
||||
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED) String id;
|
||||
@Column String firstname;
|
||||
|
||||
public static final String uuid() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public static Thing random() {
|
||||
return new Thing(uuid(), RNG.nextInt());
|
||||
public static Person random() {
|
||||
return new Person(uuid(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + number;
|
||||
result = prime * result + ((stuff == null) ? 0 : stuff.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Thing other = (Thing) obj;
|
||||
if (number != other.number)
|
||||
return false;
|
||||
if (stuff == null) {
|
||||
if (other.stuff != null)
|
||||
return false;
|
||||
} else if (!stuff.equals(other.stuff))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ThingListener extends TestListener implements WriteListener<Thing>, DeletionListener<Thing> {
|
||||
public static class PersonListener extends TestListener implements WriteListener<Person>, DeletionListener<Person> {
|
||||
|
||||
public volatile Exception exception;
|
||||
public volatile Collection<Thing> entities;
|
||||
public volatile Collection<Person> entities;
|
||||
public volatile boolean success;
|
||||
|
||||
@Override
|
||||
public void onWriteComplete(Collection<Thing> entities) {
|
||||
public void onWriteComplete(Collection<Person> entities) {
|
||||
|
||||
this.entities = entities;
|
||||
this.success = true;
|
||||
countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeletionComplete(Collection<Thing> entities) {
|
||||
public void onDeletionComplete(Collection<Person> entities) {
|
||||
|
||||
this.entities = entities;
|
||||
this.success = true;
|
||||
countDown();
|
||||
@@ -312,6 +287,7 @@ public class AsynchronousCassandraTemplateIntegrationTests extends AbstractSprin
|
||||
|
||||
@Override
|
||||
public void onException(Exception x) {
|
||||
|
||||
this.exception = x;
|
||||
this.success = false;
|
||||
countDown();
|
||||
|
||||
Reference in New Issue
Block a user