DATACASS-402 - Extend exception translation for exceptions that map currently to CassandraUncategorizedException.
We now provide a more fine-grained exception translation for exceptions that previously mapped to CassandraUncategorizedException. Existing translation to more specific exception does not change. The following translation rules are introduced by this change: * OverloadedException and BootstrappingException map to TransientDataAccessResourceException * NoHostAvailableException, BusyPoolException, ConnectionException, BusyConnectionException map to CassandraConnectionFailureException * QueryConsistencyException, FunctionExecutionException map to DataAccessResourceFailureException
This commit is contained in:
@@ -32,6 +32,7 @@ import org.springframework.cassandra.core.RowMapperResultSetExtractor;
|
||||
import org.springframework.cassandra.core.SingleColumnRowMapper;
|
||||
import org.springframework.cassandra.core.session.DefaultSessionFactory;
|
||||
import org.springframework.cassandra.core.session.SessionFactory;
|
||||
import org.springframework.cassandra.core.support.CQLExceptionTranslator;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -67,7 +68,7 @@ public class CassandraAccessor implements InitializingBean {
|
||||
/** Logger available to subclasses */
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
protected CassandraExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
|
||||
protected CQLExceptionTranslator exceptionTranslator = new CassandraExceptionTranslator();
|
||||
|
||||
/**
|
||||
* If this variable is set to a non-negative value, it will be used for setting the {@code fetchSize} property on
|
||||
@@ -121,10 +122,11 @@ public class CassandraAccessor implements InitializingBean {
|
||||
* Exception Hierarchy.
|
||||
*
|
||||
* @param exceptionTranslator exception translator to set; must not be {@literal null}.
|
||||
* @see org.springframework.cassandra.support.CassandraExceptionTranslator
|
||||
* @see CQLExceptionTranslator
|
||||
*/
|
||||
public void setExceptionTranslator(CassandraExceptionTranslator exceptionTranslator) {
|
||||
Assert.notNull(exceptionTranslator, "CassandraExceptionTranslator must not be null");
|
||||
public void setExceptionTranslator(CQLExceptionTranslator exceptionTranslator) {
|
||||
|
||||
Assert.notNull(exceptionTranslator, "CQLExceptionTranslator must not be null");
|
||||
this.exceptionTranslator = exceptionTranslator;
|
||||
}
|
||||
|
||||
@@ -133,11 +135,11 @@ public class CassandraAccessor implements InitializingBean {
|
||||
* Exception Hierarchy.
|
||||
*
|
||||
* @return the Cassandra exception translator.
|
||||
* @see org.springframework.cassandra.support.CassandraExceptionTranslator
|
||||
* @see CQLExceptionTranslator
|
||||
*/
|
||||
public CassandraExceptionTranslator getExceptionTranslator() {
|
||||
Assert.state(this.exceptionTranslator != null,
|
||||
"CassandraExceptionTranslator was not properly initialized");
|
||||
public CQLExceptionTranslator getExceptionTranslator() {
|
||||
|
||||
Assert.state(this.exceptionTranslator != null, "CQLExceptionTranslator was not properly initialized");
|
||||
|
||||
return this.exceptionTranslator;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
*
|
||||
* Copyright 2013-2017 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.
|
||||
@@ -15,130 +15,168 @@
|
||||
*/
|
||||
package org.springframework.cassandra.support;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.cassandra.core.support.CQLExceptionTranslator;
|
||||
import org.springframework.cassandra.support.exception.CassandraAuthenticationException;
|
||||
import org.springframework.cassandra.support.exception.CassandraConnectionFailureException;
|
||||
import org.springframework.cassandra.support.exception.CassandraInsufficientReplicasAvailableException;
|
||||
import org.springframework.cassandra.support.exception.CassandraInternalException;
|
||||
import org.springframework.cassandra.support.exception.CassandraInvalidConfigurationInQueryException;
|
||||
import org.springframework.cassandra.support.exception.CassandraInvalidQueryException;
|
||||
import org.springframework.cassandra.support.exception.CassandraKeyspaceExistsException;
|
||||
import org.springframework.cassandra.support.exception.CassandraQuerySyntaxException;
|
||||
import org.springframework.cassandra.support.exception.CassandraReadTimeoutException;
|
||||
import org.springframework.cassandra.support.exception.CassandraTableExistsException;
|
||||
import org.springframework.cassandra.support.exception.CassandraTraceRetrievalException;
|
||||
import org.springframework.cassandra.support.exception.CassandraTruncateException;
|
||||
import org.springframework.cassandra.support.exception.CassandraTypeMismatchException;
|
||||
import org.springframework.cassandra.support.exception.CassandraUnauthorizedException;
|
||||
import org.springframework.cassandra.support.exception.CassandraUncategorizedException;
|
||||
import org.springframework.cassandra.support.exception.CassandraWriteTimeoutException;
|
||||
import org.springframework.cassandra.support.exception.*;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.datastax.driver.core.WriteType;
|
||||
import com.datastax.driver.core.exceptions.AlreadyExistsException;
|
||||
import com.datastax.driver.core.exceptions.AuthenticationException;
|
||||
import com.datastax.driver.core.exceptions.DriverException;
|
||||
import com.datastax.driver.core.exceptions.DriverInternalError;
|
||||
import com.datastax.driver.core.exceptions.InvalidConfigurationInQueryException;
|
||||
import com.datastax.driver.core.exceptions.InvalidQueryException;
|
||||
import com.datastax.driver.core.exceptions.InvalidTypeException;
|
||||
import com.datastax.driver.core.exceptions.NoHostAvailableException;
|
||||
import com.datastax.driver.core.exceptions.ReadTimeoutException;
|
||||
import com.datastax.driver.core.exceptions.SyntaxError;
|
||||
import com.datastax.driver.core.exceptions.TraceRetrievalException;
|
||||
import com.datastax.driver.core.exceptions.TruncateException;
|
||||
import com.datastax.driver.core.exceptions.UnauthorizedException;
|
||||
import com.datastax.driver.core.exceptions.UnavailableException;
|
||||
import com.datastax.driver.core.exceptions.WriteTimeoutException;
|
||||
import com.datastax.driver.core.exceptions.*;
|
||||
|
||||
/**
|
||||
* Simple {@link PersistenceExceptionTranslator} for Cassandra.
|
||||
* <p>
|
||||
* Convert the given runtime exception to an appropriate exception from the {@code org.springframework.dao} hierarchy.
|
||||
* Return {@literal null} if no translation is appropriate: any other exception may have resulted from user code, and
|
||||
* should not be translated.
|
||||
*
|
||||
* Preserves exception if it's already a {@link DataAccessException} and ignores non {@link DriverException}s returning
|
||||
* {@literal null}. Falls back to {@link CassandraUncategorizedException} in case there's no mapping to a more detailed
|
||||
* exception.
|
||||
*
|
||||
* @author Alex Shvid
|
||||
* @author Matthew T. Adams
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CassandraExceptionTranslator implements CQLExceptionTranslator {
|
||||
|
||||
@Override
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
private static final Set<String> CONNECTION_FAILURE_TYPES = new HashSet<>(
|
||||
Arrays.asList("NoHostAvailableException", "ConnectionException", "OperationTimedOutException",
|
||||
"TransportException", "BusyConnectionException", "BusyPoolException"));
|
||||
|
||||
if (ex instanceof DataAccessException) {
|
||||
return (DataAccessException) ex;
|
||||
private static final Set<String> RESOURCE_FAILURE_TYPES = new HashSet<>(
|
||||
Arrays.asList("ReadFailureException", "WriteFailureException", "FunctionExecutionException"));
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(java.lang.RuntimeException)
|
||||
*/
|
||||
@Override
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException exception) {
|
||||
|
||||
if (exception instanceof DataAccessException) {
|
||||
return (DataAccessException) exception;
|
||||
}
|
||||
|
||||
if (!(ex instanceof DriverException)) {
|
||||
if (!(exception instanceof DriverException)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return translate(null, null, (DriverException) ex);
|
||||
return translate(null, null, (DriverException) exception);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.cassandra.core.support.CQLExceptionTranslator#translate(java.lang.String, java.lang.String, com.datastax.driver.core.exceptions.DriverException)
|
||||
*/
|
||||
@Override
|
||||
public DataAccessException translate(String task, String cql, DriverException ex) {
|
||||
public DataAccessException translate(String task, String cql, DriverException exception) {
|
||||
|
||||
String message = buildMessage(task, cql, ex);
|
||||
String message = buildMessage(task, cql, exception);
|
||||
|
||||
// Remember: subclasses must come before superclasses, otherwise the
|
||||
// superclass would match before the subclass!
|
||||
|
||||
if (ex instanceof AuthenticationException) {
|
||||
return new CassandraAuthenticationException(((AuthenticationException) ex).getHost(), message, ex);
|
||||
if (exception instanceof AuthenticationException) {
|
||||
return new CassandraAuthenticationException(((AuthenticationException) exception).getHost(), message, exception);
|
||||
}
|
||||
if (ex instanceof DriverInternalError) {
|
||||
return new CassandraInternalException(message, ex);
|
||||
}
|
||||
if (ex instanceof InvalidTypeException) {
|
||||
return new CassandraTypeMismatchException(message, ex);
|
||||
}
|
||||
if (ex instanceof NoHostAvailableException) {
|
||||
return new CassandraConnectionFailureException(((NoHostAvailableException) ex).getErrors(), message, ex);
|
||||
}
|
||||
if (ex instanceof ReadTimeoutException) {
|
||||
return new CassandraReadTimeoutException(((ReadTimeoutException) ex).wasDataRetrieved(), message, ex);
|
||||
}
|
||||
if (ex instanceof WriteTimeoutException) {
|
||||
WriteType writeType = ((WriteTimeoutException) ex).getWriteType();
|
||||
return new CassandraWriteTimeoutException(writeType == null ? null : writeType.name(), message, ex);
|
||||
}
|
||||
if (ex instanceof TruncateException) {
|
||||
return new CassandraTruncateException(message, ex);
|
||||
}
|
||||
if (ex instanceof UnavailableException) {
|
||||
UnavailableException ux = (UnavailableException) ex;
|
||||
return new CassandraInsufficientReplicasAvailableException(ux.getRequiredReplicas(), ux.getAliveReplicas(),
|
||||
message, ex);
|
||||
}
|
||||
if (ex instanceof AlreadyExistsException) {
|
||||
AlreadyExistsException aex = (AlreadyExistsException) ex;
|
||||
|
||||
return aex.wasTableCreation() ? new CassandraTableExistsException(aex.getTable(), message, ex)
|
||||
: new CassandraKeyspaceExistsException(aex.getKeyspace(), message, ex);
|
||||
if (exception instanceof DriverInternalError) {
|
||||
return new CassandraInternalException(message, exception);
|
||||
}
|
||||
if (ex instanceof InvalidConfigurationInQueryException) {
|
||||
return new CassandraInvalidConfigurationInQueryException(message, ex);
|
||||
|
||||
if (exception instanceof InvalidTypeException) {
|
||||
return new CassandraTypeMismatchException(message, exception);
|
||||
}
|
||||
if (ex instanceof InvalidQueryException) {
|
||||
return new CassandraInvalidQueryException(message, ex);
|
||||
|
||||
if (exception instanceof ReadTimeoutException) {
|
||||
return new CassandraReadTimeoutException(((ReadTimeoutException) exception).wasDataRetrieved(), message,
|
||||
exception);
|
||||
}
|
||||
if (ex instanceof SyntaxError) {
|
||||
return new CassandraQuerySyntaxException(message, ex);
|
||||
|
||||
if (exception instanceof WriteTimeoutException) {
|
||||
|
||||
WriteType writeType = ((WriteTimeoutException) exception).getWriteType();
|
||||
return new CassandraWriteTimeoutException(writeType == null ? null : writeType.name(), message, exception);
|
||||
}
|
||||
if (ex instanceof UnauthorizedException) {
|
||||
return new CassandraUnauthorizedException(message, ex);
|
||||
|
||||
if (exception instanceof TruncateException) {
|
||||
return new CassandraTruncateException(message, exception);
|
||||
}
|
||||
if (ex instanceof TraceRetrievalException) {
|
||||
return new CassandraTraceRetrievalException(message, ex);
|
||||
|
||||
if (exception instanceof UnavailableException) {
|
||||
|
||||
UnavailableException ux = (UnavailableException) exception;
|
||||
return new CassandraInsufficientReplicasAvailableException(ux.getRequiredReplicas(), ux.getAliveReplicas(),
|
||||
message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof OverloadedException || exception instanceof BootstrappingException) {
|
||||
return new TransientDataAccessResourceException(message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof AlreadyExistsException) {
|
||||
|
||||
AlreadyExistsException aex = (AlreadyExistsException) exception;
|
||||
|
||||
return aex.wasTableCreation() ? new CassandraTableExistsException(aex.getTable(), message, exception)
|
||||
: new CassandraKeyspaceExistsException(aex.getKeyspace(), message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof InvalidConfigurationInQueryException) {
|
||||
return new CassandraInvalidConfigurationInQueryException(message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof InvalidQueryException) {
|
||||
return new CassandraInvalidQueryException(message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof SyntaxError) {
|
||||
return new CassandraQuerySyntaxException(message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof UnauthorizedException) {
|
||||
return new CassandraUnauthorizedException(message, exception);
|
||||
}
|
||||
|
||||
if (exception instanceof TraceRetrievalException) {
|
||||
return new CassandraTraceRetrievalException(message, exception);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (exception instanceof NoHostAvailableException) {
|
||||
return new CassandraConnectionFailureException(((NoHostAvailableException) exception).getErrors(),message,
|
||||
exception);
|
||||
}
|
||||
|
||||
String exceptionType = ClassUtils.getShortName(ClassUtils.getUserClass(exception.getClass()));
|
||||
|
||||
if (CONNECTION_FAILURE_TYPES.contains(exceptionType)) {
|
||||
|
||||
Map<InetSocketAddress, Throwable> errorMap = Collections.emptyMap();
|
||||
|
||||
if (exception instanceof CoordinatorException) {
|
||||
CoordinatorException cx = (CoordinatorException) exception;
|
||||
errorMap = Collections.singletonMap(cx.getAddress(), exception);
|
||||
}
|
||||
|
||||
return new CassandraConnectionFailureException(errorMap, message, exception);
|
||||
}
|
||||
|
||||
if (RESOURCE_FAILURE_TYPES.contains(exceptionType)) {
|
||||
return new DataAccessResourceFailureException(message, exception);
|
||||
}
|
||||
|
||||
// unknown or unhandled exception
|
||||
return new CassandraUncategorizedException(message, ex);
|
||||
return new CassandraUncategorizedException(message, exception);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,7 +184,7 @@ public class CassandraExceptionTranslator implements CQLExceptionTranslator {
|
||||
* <p>
|
||||
* To be called by translator subclasses when creating an instance of a generic
|
||||
* {@link org.springframework.dao.DataAccessException} class.
|
||||
*
|
||||
*
|
||||
* @param task readable text describing the task being attempted
|
||||
* @param cql the CQL statement that caused the problem (may be {@code null})
|
||||
* @param ex the offending {@code DriverException}
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.datastax.driver.core.Session;
|
||||
* {@link CassandraAccessor} class.
|
||||
*
|
||||
* @author John Blum
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CassandraAccessorUnitTests {
|
||||
@@ -74,7 +75,7 @@ public class CassandraAccessorUnitTests {
|
||||
cassandraAccessor.setExceptionTranslator(null);
|
||||
fail("Missing IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e).hasMessageContaining("CassandraExceptionTranslator must not be null");
|
||||
assertThat(e).hasMessageContaining("must not be null");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,18 +16,26 @@
|
||||
package org.springframework.cassandra.support;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.Assume.*;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.cassandra.support.exception.CassandraInvalidConfigurationInQueryException;
|
||||
import org.springframework.cassandra.support.exception.CassandraInvalidQueryException;
|
||||
import org.springframework.cassandra.support.exception.CassandraKeyspaceExistsException;
|
||||
import org.springframework.cassandra.support.exception.CassandraSchemaElementExistsException;
|
||||
import org.springframework.cassandra.support.exception.CassandraTableExistsException;
|
||||
import org.springframework.cassandra.support.exception.*;
|
||||
import org.springframework.cassandra.support.exception.CassandraSchemaElementExistsException.ElementType;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.datastax.driver.core.exceptions.AlreadyExistsException;
|
||||
import com.datastax.driver.core.exceptions.InvalidConfigurationInQueryException;
|
||||
import com.datastax.driver.core.exceptions.InvalidQueryException;
|
||||
import com.datastax.driver.core.ConsistencyLevel;
|
||||
import com.datastax.driver.core.DataType;
|
||||
import com.datastax.driver.core.ProtocolVersion;
|
||||
import com.datastax.driver.core.WriteType;
|
||||
import com.datastax.driver.core.exceptions.*;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link CassandraExceptionTranslator}
|
||||
@@ -37,63 +45,303 @@ import com.datastax.driver.core.exceptions.InvalidQueryException;
|
||||
*/
|
||||
public class CassandraExceptionTranslatorUnitTests {
|
||||
|
||||
CassandraExceptionTranslator tx = new CassandraExceptionTranslator();
|
||||
InetSocketAddress socketAddress = new InetSocketAddress("localhost", 42);
|
||||
CassandraExceptionTranslator sut = new CassandraExceptionTranslator();
|
||||
|
||||
@Test
|
||||
public void testTableExistsException() {
|
||||
String keyspace = "";
|
||||
String table = "tbl";
|
||||
AlreadyExistsException cx = new AlreadyExistsException(keyspace, table);
|
||||
DataAccessException dax = tx.translateExceptionIfPossible(cx);
|
||||
assertThat(dax).isNotNull();
|
||||
assertThat(dax instanceof CassandraTableExistsException).isTrue();
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateAuthenticationException() {
|
||||
|
||||
CassandraTableExistsException x = (CassandraTableExistsException) dax;
|
||||
assertThat(x.getTableName()).isEqualTo(table);
|
||||
assertThat(x.getElementName()).isEqualTo(x.getTableName());
|
||||
assertThat(x.getElementType()).isEqualTo(CassandraSchemaElementExistsException.ElementType.TABLE);
|
||||
assertThat(x.getCause()).isEqualTo(cx);
|
||||
DataAccessException result = sut
|
||||
.translateExceptionIfPossible(new AuthenticationException(socketAddress, "message"));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraAuthenticationException.class)
|
||||
.hasMessageStartingWith("Authentication error on host").hasCauseInstanceOf(AuthenticationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyspaceExistsException() {
|
||||
String keyspace = "ks";
|
||||
String table = "";
|
||||
AlreadyExistsException cx = new AlreadyExistsException(keyspace, table);
|
||||
DataAccessException dax = tx.translateExceptionIfPossible(cx);
|
||||
assertThat(dax).isNotNull();
|
||||
assertThat(dax instanceof CassandraKeyspaceExistsException).isTrue();
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateCassandraInternalException() {
|
||||
|
||||
CassandraKeyspaceExistsException x = (CassandraKeyspaceExistsException) dax;
|
||||
assertThat(x.getKeyspaceName()).isEqualTo(keyspace);
|
||||
assertThat(x.getElementName()).isEqualTo(x.getKeyspaceName());
|
||||
assertThat(x.getElementType()).isEqualTo(CassandraSchemaElementExistsException.ElementType.KEYSPACE);
|
||||
assertThat(x.getCause()).isEqualTo(cx);
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new DriverInternalError("message"));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraInternalException.class).hasMessageStartingWith("message")
|
||||
.hasCauseInstanceOf(DriverInternalError.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidConfigurationInQueryException() {
|
||||
String msg = "msg";
|
||||
InvalidQueryException cx = new InvalidConfigurationInQueryException(null, msg);
|
||||
DataAccessException dax = tx.translateExceptionIfPossible(cx);
|
||||
assertThat(dax).isNotNull();
|
||||
assertThat(dax instanceof CassandraInvalidConfigurationInQueryException).isTrue();
|
||||
assertThat(dax.getCause()).isEqualTo(cx);
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateTraceRetrievalException() {
|
||||
|
||||
cx = new InvalidQueryException(msg);
|
||||
dax = tx.translateExceptionIfPossible(cx);
|
||||
assertThat(dax).isNotNull();
|
||||
assertThat(dax instanceof CassandraInvalidQueryException).isTrue();
|
||||
assertThat(dax.getCause()).isEqualTo(cx);
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new TraceRetrievalException("message"));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraTraceRetrievalException.class).hasMessageStartingWith("message")
|
||||
.hasCauseInstanceOf(TraceRetrievalException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateNoHostAvailableException() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(
|
||||
new NoHostAvailableException(Collections.singletonMap(socketAddress, new IllegalStateException())));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraConnectionFailureException.class)
|
||||
.hasMessageStartingWith("All host(s) tried").hasCauseInstanceOf(NoHostAvailableException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateInvalidQueryException() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new InvalidQueryException(socketAddress, "message"));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraInvalidQueryException.class).hasMessageStartingWith("message")
|
||||
.hasCauseInstanceOf(InvalidQueryException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateInvalidConfigurationInQueryException() {
|
||||
|
||||
DataAccessException result = sut
|
||||
.translateExceptionIfPossible(new InvalidConfigurationInQueryException(socketAddress, "message"));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraInvalidConfigurationInQueryException.class)
|
||||
.hasMessageStartingWith("message").hasCauseInstanceOf(InvalidConfigurationInQueryException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateUnauthorizedException() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new UnauthorizedException(socketAddress, "message"));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraUnauthorizedException.class).hasMessageStartingWith("message")
|
||||
.hasCauseInstanceOf(UnauthorizedException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateSyntaxError() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new SyntaxError(socketAddress, "message"));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraQuerySyntaxException.class).hasMessageStartingWith("message")
|
||||
.hasCauseInstanceOf(SyntaxError.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateKeyspaceExistsException() {
|
||||
|
||||
AlreadyExistsException cx = new AlreadyExistsException("keyspace", "");
|
||||
DataAccessException result = sut.translateExceptionIfPossible(cx);
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraKeyspaceExistsException.class)
|
||||
.hasMessageStartingWith("Keyspace keyspace already exists").hasCauseInstanceOf(AlreadyExistsException.class);
|
||||
|
||||
CassandraSchemaElementExistsException exception = (CassandraSchemaElementExistsException) result;
|
||||
|
||||
assertThat(exception.getElementName()).isEqualTo("keyspace");
|
||||
assertThat(exception.getElementType()).isEqualTo(ElementType.KEYSPACE);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateTableExistsException() {
|
||||
|
||||
AlreadyExistsException cx = new AlreadyExistsException("keyspace", "table");
|
||||
DataAccessException result = sut.translateExceptionIfPossible(cx);
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraTableExistsException.class)
|
||||
.hasMessageStartingWith("Table keyspace.table already exists").hasCauseInstanceOf(AlreadyExistsException.class);
|
||||
|
||||
CassandraSchemaElementExistsException exception = (CassandraSchemaElementExistsException) result;
|
||||
|
||||
assertThat(exception.getElementName()).isEqualTo("table");
|
||||
assertThat(exception.getElementType()).isEqualTo(ElementType.TABLE);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateInvalidTypeException() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new InvalidTypeException("message"));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraTypeMismatchException.class).hasMessageStartingWith("message")
|
||||
.hasCauseInstanceOf(InvalidTypeException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateUnavailableException() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new UnavailableException(ConsistencyLevel.ALL, 5, 1));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraInsufficientReplicasAvailableException.class)
|
||||
.hasMessageStartingWith("Not enough replicas available").hasCauseInstanceOf(UnavailableException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateBootstrappingException() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new BootstrappingException(socketAddress, "message"));
|
||||
|
||||
assertThat(result).isInstanceOf(TransientDataAccessResourceException.class).hasMessageStartingWith("Queried host")
|
||||
.hasCauseInstanceOf(BootstrappingException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateOverloadedException() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new OverloadedException(socketAddress, "message"));
|
||||
|
||||
assertThat(result).isInstanceOf(TransientDataAccessResourceException.class).hasMessageStartingWith("Queried host")
|
||||
.hasCauseInstanceOf(OverloadedException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateTruncateException() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new TruncateException(socketAddress, "message"));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraTruncateException.class).hasMessageStartingWith("message")
|
||||
.hasCauseInstanceOf(TruncateException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateWriteFailureException() {
|
||||
|
||||
DataAccessException result = sut
|
||||
.translateExceptionIfPossible(new WriteFailureException(ConsistencyLevel.ALL, WriteType.BATCH, 1, 5, 1));
|
||||
|
||||
assertThat(result).isInstanceOf(DataAccessResourceFailureException.class)
|
||||
.hasMessageStartingWith("Cassandra failure during").hasCauseInstanceOf(WriteFailureException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateReadFailureException() {
|
||||
|
||||
DataAccessException result = sut
|
||||
.translateExceptionIfPossible(new ReadFailureException(ConsistencyLevel.ALL, 1, 5, 1, true));
|
||||
|
||||
assertThat(result).isInstanceOf(DataAccessResourceFailureException.class)
|
||||
.hasMessageStartingWith("Cassandra failure during").hasCauseInstanceOf(ReadFailureException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateWriteTimeoutException() {
|
||||
|
||||
DataAccessException result = sut
|
||||
.translateExceptionIfPossible(new WriteTimeoutException(ConsistencyLevel.ALL, WriteType.BATCH, 1, 5));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraWriteTimeoutException.class)
|
||||
.hasMessageStartingWith("Cassandra timeout during").hasCauseInstanceOf(WriteTimeoutException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateReadTimeoutException() {
|
||||
|
||||
DataAccessException result = sut
|
||||
.translateExceptionIfPossible(new ReadTimeoutException(ConsistencyLevel.ALL, 1, 5, true));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraReadTimeoutException.class)
|
||||
.hasMessageStartingWith("Cassandra timeout during").hasCauseInstanceOf(ReadTimeoutException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateFunctionExecutionException() {
|
||||
|
||||
DataAccessException result = sut
|
||||
.translateExceptionIfPossible(new FunctionExecutionException(socketAddress, "message"));
|
||||
|
||||
assertThat(result).isInstanceOf(DataAccessResourceFailureException.class).hasMessageStartingWith("message")
|
||||
.hasCauseInstanceOf(FunctionExecutionException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldTranslateBusyPoolException() throws Exception {
|
||||
|
||||
assumeTrue(
|
||||
ClassUtils.isPresent("com.datastax.driver.core.exceptions.BusyPoolException", getClass().getClassLoader()));
|
||||
|
||||
DriverException exception = createInstance("com.datastax.driver.core.exceptions.BusyPoolException",
|
||||
new Class[] { InetSocketAddress.class, Integer.TYPE }, socketAddress, 5);
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(exception);
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraConnectionFailureException.class).hasMessageContaining("Pool is busy")
|
||||
.hasCauseInstanceOf(exception.getClass());
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateConnectionException() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new ConnectionException(socketAddress, "message"));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraConnectionFailureException.class).hasMessageContaining("] message")
|
||||
.hasCauseInstanceOf(ConnectionException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateBusyConnectionException() {
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(new BusyConnectionException(socketAddress));
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraConnectionFailureException.class)
|
||||
.hasMessageContaining("Connection has run out of stream").hasCauseInstanceOf(BusyConnectionException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldTranslateFrameTooLongException() throws Exception {
|
||||
|
||||
assumeTrue(
|
||||
ClassUtils.isPresent("com.datastax.driver.core.exceptions.FrameTooLongException", getClass().getClassLoader()));
|
||||
|
||||
DriverException exception = createInstance("com.datastax.driver.core.exceptions.FrameTooLongException",
|
||||
new Class[] { Integer.TYPE }, 5);
|
||||
|
||||
DataAccessException result = sut.translateExceptionIfPossible(exception);
|
||||
|
||||
assertThat(result).isInstanceOf(CassandraUncategorizedException.class).hasCauseInstanceOf(exception.getClass());
|
||||
}
|
||||
|
||||
@Test // DATACASS-402
|
||||
public void shouldTranslateToUncategorized() {
|
||||
|
||||
assertThat(sut.translateExceptionIfPossible(
|
||||
new CodecNotFoundException("message", DataType.ascii(), TypeToken.of(Class.class))))
|
||||
.isInstanceOf(CassandraUncategorizedException.class);
|
||||
|
||||
assertThat(sut.translateExceptionIfPossible(
|
||||
new UnsupportedProtocolVersionException(socketAddress, ProtocolVersion.NEWEST_SUPPORTED, ProtocolVersion.V1)))
|
||||
.isInstanceOf(CassandraUncategorizedException.class);
|
||||
|
||||
assertThat(sut.translateExceptionIfPossible(new UnpreparedException(socketAddress, "message")))
|
||||
.isInstanceOf(CassandraUncategorizedException.class);
|
||||
|
||||
assertThat(sut.translateExceptionIfPossible(new PagingStateException("message")))
|
||||
.isInstanceOf(CassandraUncategorizedException.class);
|
||||
|
||||
assertThat(sut.translateExceptionIfPossible(new UnresolvedUserTypeException("keyspace", "message")))
|
||||
.isInstanceOf(CassandraUncategorizedException.class);
|
||||
|
||||
assertThat(
|
||||
sut.translateExceptionIfPossible(new UnsupportedFeatureException(ProtocolVersion.NEWEST_SUPPORTED, "message")))
|
||||
.isInstanceOf(CassandraUncategorizedException.class);
|
||||
|
||||
assertThat(sut.translateExceptionIfPossible(new UnresolvedUserTypeException("keyspace", "message")))
|
||||
.isInstanceOf(CassandraUncategorizedException.class);
|
||||
}
|
||||
|
||||
@Test // DATACASS-335
|
||||
public void shouldTranslateWithCqlMessage() {
|
||||
|
||||
InvalidQueryException cx = new InvalidConfigurationInQueryException(null, "err");
|
||||
DataAccessException dax = tx.translate("Query", "SELECT * FROM person", cx);
|
||||
DataAccessException dax = sut.translate("Query", "SELECT * FROM person", cx);
|
||||
|
||||
assertThat(dax).hasRootCauseInstanceOf(InvalidQueryException.class).hasMessage(
|
||||
"Query; CQL [SELECT * FROM person]; err; nested exception is com.datastax.driver.core.exceptions.InvalidConfigurationInQueryException: err");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T createInstance(String className, Class<?> argTypes[], Object... args)
|
||||
throws ReflectiveOperationException {
|
||||
|
||||
Class<T> exceptionClass = (Class) ClassUtils.forName(className, getClass().getClassLoader());
|
||||
Constructor<T> constructor = exceptionClass.getDeclaredConstructor(argTypes);
|
||||
|
||||
return constructor.newInstance(args);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user