Browse Source

DATAMONGO-2045 - Add session & transaction specific error codes for exception translation.

Original pull request: #592.
pull/593/merge
Christoph Strobl 7 years ago committed by Mark Paluch
parent
commit
c2373d05fe
  1. 47
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionException.java
  2. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoExceptionTranslator.java
  3. 53
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/MongoDbErrorCodes.java
  4. 31
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoExceptionTranslatorUnitTests.java

47
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionException.java

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
/*
* Copyright 2018 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.mongodb;
import org.springframework.lang.Nullable;
/**
* A specific {@link ClientSessionException} related to issues with a transaction such as aborted or non existing
* transactions.
*
* @author Christoph Strobl
* @since 2.1
*/
public class MongoTransactionException extends ClientSessionException {
/**
* Constructor for {@link MongoTransactionException}.
*
* @param msg the detail message. Must not be {@literal null}.
*/
public MongoTransactionException(String msg) {
super(msg);
}
/**
* Constructor for {@link ClientSessionException}.
*
* @param msg the detail message. Can be {@literal null}.
* @param cause the root cause. Can be {@literal null}.
*/
public MongoTransactionException(@Nullable String msg, @Nullable Throwable cause) {
super(msg, cause);
}
}

5
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoExceptionTranslator.java

@ -30,6 +30,7 @@ import org.springframework.dao.PermissionDeniedDataAccessException; @@ -30,6 +30,7 @@ import org.springframework.dao.PermissionDeniedDataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.BulkOperationException;
import org.springframework.data.mongodb.ClientSessionException;
import org.springframework.data.mongodb.MongoTransactionException;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.data.mongodb.util.MongoDbErrorCodes;
import org.springframework.lang.Nullable;
@ -128,6 +129,10 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator @@ -128,6 +129,10 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
} else if (MongoDbErrorCodes.isPermissionDeniedCode(code)) {
return new PermissionDeniedDataAccessException(ex.getMessage(), ex);
} else if (MongoDbErrorCodes.isClientSessionFailureCode(code)) {
return new ClientSessionException(ex.getMessage(), ex);
} else if (MongoDbErrorCodes.isTransactionFailureCode(code)) {
return new MongoTransactionException(ex.getMessage(), ex);
}
return new UncategorizedMongoDbException(ex.getMessage(), ex);
}

53
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/MongoDbErrorCodes.java

@ -33,12 +33,14 @@ public final class MongoDbErrorCodes { @@ -33,12 +33,14 @@ public final class MongoDbErrorCodes {
static HashMap<Integer, String> duplicateKeyCodes;
static HashMap<Integer, String> invalidDataAccessApiUsageExeption;
static HashMap<Integer, String> permissionDeniedCodes;
static HashMap<Integer, String> clientSessionCodes;
static HashMap<Integer, String> transactionCodes;
static HashMap<Integer, String> errorCodes;
static {
dataAccessResourceFailureCodes = new HashMap<Integer, String>(10);
dataAccessResourceFailureCodes = new HashMap<>(10);
dataAccessResourceFailureCodes.put(6, "HostUnreachable");
dataAccessResourceFailureCodes.put(7, "HostNotFound");
dataAccessResourceFailureCodes.put(89, "NetworkTimeout");
@ -52,7 +54,7 @@ public final class MongoDbErrorCodes { @@ -52,7 +54,7 @@ public final class MongoDbErrorCodes {
dataAccessResourceFailureCodes.put(13441, "BadOffsetInFile");
dataAccessResourceFailureCodes.put(13640, "DataFileHeaderCorrupt");
dataIntegrityViolationCodes = new HashMap<Integer, String>(6);
dataIntegrityViolationCodes = new HashMap<>(6);
dataIntegrityViolationCodes.put(67, "CannotCreateIndex");
dataIntegrityViolationCodes.put(68, "IndexAlreadyExists");
dataIntegrityViolationCodes.put(85, "IndexOptionsConflict");
@ -60,13 +62,13 @@ public final class MongoDbErrorCodes { @@ -60,13 +62,13 @@ public final class MongoDbErrorCodes {
dataIntegrityViolationCodes.put(112, "WriteConflict");
dataIntegrityViolationCodes.put(117, "ConflictingOperationInProgress");
duplicateKeyCodes = new HashMap<Integer, String>(3);
duplicateKeyCodes = new HashMap<>(3);
duplicateKeyCodes.put(3, "OBSOLETE_DuplicateKey");
duplicateKeyCodes.put(84, "DuplicateKeyValue");
duplicateKeyCodes.put(11000, "DuplicateKey");
duplicateKeyCodes.put(11001, "DuplicateKey");
invalidDataAccessApiUsageExeption = new HashMap<Integer, String>();
invalidDataAccessApiUsageExeption = new HashMap<>();
invalidDataAccessApiUsageExeption.put(5, "GraphContainsCycle");
invalidDataAccessApiUsageExeption.put(9, "FailedToParse");
invalidDataAccessApiUsageExeption.put(14, "TypeMismatch");
@ -99,7 +101,7 @@ public final class MongoDbErrorCodes { @@ -99,7 +101,7 @@ public final class MongoDbErrorCodes {
invalidDataAccessApiUsageExeption.put(17280, "KeyTooLong");
invalidDataAccessApiUsageExeption.put(13334, "ShardKeyTooBig");
permissionDeniedCodes = new HashMap<Integer, String>();
permissionDeniedCodes = new HashMap<>();
permissionDeniedCodes.put(11, "UserNotFound");
permissionDeniedCodes.put(18, "AuthenticationFailed");
permissionDeniedCodes.put(31, "RoleNotFound");
@ -109,12 +111,29 @@ public final class MongoDbErrorCodes { @@ -109,12 +111,29 @@ public final class MongoDbErrorCodes {
permissionDeniedCodes.put(16704, "CannotAuthenticateToAdminDB");
permissionDeniedCodes.put(16705, "CannotAuthenticateToAdminDB");
errorCodes = new HashMap<Integer, String>();
clientSessionCodes = new HashMap<>();
clientSessionCodes.put(206, "NoSuchSession");
clientSessionCodes.put(213, "DuplicateSession");
clientSessionCodes.put(228, "SessionTransferIncomplete");
clientSessionCodes.put(264, "TooManyLogicalSessions");
transactionCodes = new HashMap<>();
transactionCodes.put(217, "IncompleteTransactionHistory");
transactionCodes.put(225, "TransactionTooOld");
transactionCodes.put(244, "TransactionAborted");
transactionCodes.put(251, "NoSuchTransaction");
transactionCodes.put(256, "TransactionCommitted");
transactionCodes.put(257, "TransactionToLarge");
transactionCodes.put(263, "OperationNotSupportedInTransaction");
transactionCodes.put(267, "PreparedTransactionInProgress");
errorCodes = new HashMap<>();
errorCodes.putAll(dataAccessResourceFailureCodes);
errorCodes.putAll(dataIntegrityViolationCodes);
errorCodes.putAll(duplicateKeyCodes);
errorCodes.putAll(invalidDataAccessApiUsageExeption);
errorCodes.putAll(permissionDeniedCodes);
errorCodes.putAll(clientSessionCodes);
}
public static boolean isDataIntegrityViolationCode(@Nullable Integer errorCode) {
@ -140,4 +159,26 @@ public final class MongoDbErrorCodes { @@ -140,4 +159,26 @@ public final class MongoDbErrorCodes {
public static String getErrorDescription(@Nullable Integer errorCode) {
return errorCode == null ? null : errorCodes.get(errorCode);
}
/**
* Check if the given error code matches a know session related error.
*
* @param errorCode the error code to check.
* @return {@literal true} if error matches.
* @since 2.1
*/
public static boolean isClientSessionFailureCode(@Nullable Integer errorCode) {
return errorCode == null ? null : clientSessionCodes.containsKey(errorCode);
}
/**
* Check if the given error code matches a know transaction related error.
*
* @param errorCode the error code to check.
* @return {@literal true} if error matches.
* @since 2.1
*/
public static boolean isTransactionFailureCode(@Nullable Integer errorCode) {
return errorCode == null ? null : transactionCodes.containsKey(errorCode);
}
}

31
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoExceptionTranslatorUnitTests.java

@ -17,25 +17,20 @@ package org.springframework.data.mongodb.core; @@ -17,25 +17,20 @@ package org.springframework.data.mongodb.core;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.net.UnknownHostException;
import com.mongodb.WriteConcern;
import org.bson.BsonDocument;
import org.bson.Document;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.core.NestedRuntimeException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.mongodb.ClientSessionException;
import org.springframework.data.mongodb.MongoTransactionException;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import com.mongodb.MongoCursorNotFoundException;
@ -135,6 +130,28 @@ public class MongoExceptionTranslatorUnitTests { @@ -135,6 +130,28 @@ public class MongoExceptionTranslatorUnitTests {
assertThat(translator.translateExceptionIfPossible(exception), is(nullValue()));
}
@Test // DATAMONGO-2045
public void translateSessionExceptions() {
checkTranslatedMongoException(ClientSessionException.class, 206);
checkTranslatedMongoException(ClientSessionException.class, 213);
checkTranslatedMongoException(ClientSessionException.class, 228);
checkTranslatedMongoException(ClientSessionException.class, 264);
}
@Test // DATAMONGO-2045
public void translateTransactionExceptions() {
checkTranslatedMongoException(MongoTransactionException.class, 217);
checkTranslatedMongoException(MongoTransactionException.class, 225);
checkTranslatedMongoException(MongoTransactionException.class, 244);
checkTranslatedMongoException(MongoTransactionException.class, 251);
checkTranslatedMongoException(MongoTransactionException.class, 256);
checkTranslatedMongoException(MongoTransactionException.class, 257);
checkTranslatedMongoException(MongoTransactionException.class, 263);
checkTranslatedMongoException(MongoTransactionException.class, 267);
}
private void checkTranslatedMongoException(Class<? extends Exception> clazz, int code) {
DataAccessException translated = translator.translateExceptionIfPossible(new MongoException(code, ""));

Loading…
Cancel
Save