Skip to content

Commit

Permalink
Polishing.
Browse files Browse the repository at this point in the history
Original pull request: #605
See #3148
See #2939
  • Loading branch information
mp911de committed Sep 4, 2024
1 parent dced760 commit 7fbd496
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,23 @@
package org.springframework.data.mongodb;

import org.springframework.dao.TransientDataAccessException;
import org.springframework.lang.Nullable;

/**
* {@link TransientDataAccessException} specific to MongoDB {@link com.mongodb.session.ClientSession} related data
* access failures such as reading data using an already closed session.
*
* @author Christoph Strobl
* @since 3.3
* @since 4.4
*/
public class TransientClientSessionException extends TransientMongoDbException {

/**
* Constructor for {@link TransientClientSessionException}.
*
* @param msg the detail message. Can be {@literal null}.
* @param cause the root cause. Can be {@literal null}.
* @param msg the detail message.
* @param cause the root cause.
*/
public TransientClientSessionException(@Nullable String msg, @Nullable Throwable cause) {
public TransientClientSessionException(String msg, Throwable cause) {
super(msg, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,24 @@
package org.springframework.data.mongodb;

import org.springframework.dao.TransientDataAccessException;
import org.springframework.lang.Nullable;

/**
* Root of the hierarchy of MongoDB specific data access exceptions that are considered transient such as
* {@link com.mongodb.MongoException MongoExceptions} carrying {@link com.mongodb.MongoException#hasErrorLabel(String)
* specific labels}.
*
* @author Christoph Strobl
* @since 3.3
* @since 4.4
*/
public class TransientMongoDbException extends TransientDataAccessException {

/**
* Constructor for {@link TransientMongoDbException}.
*
* @param msg the detail message. Can be {@literal null}.
* @param cause the root cause. Can be {@literal null}.
* @param msg the detail message.
* @param cause the root cause.
*/
public TransientMongoDbException(String msg, @Nullable Throwable cause) {
public TransientMongoDbException(String msg, Throwable cause) {
super(msg, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,14 @@
*/
public class MongoClientFactoryBean extends AbstractFactoryBean<MongoClient> implements PersistenceExceptionTranslator {

private static final PersistenceExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();

private @Nullable MongoClientSettings mongoClientSettings;
private @Nullable String host;
private @Nullable Integer port;
private @Nullable List<MongoCredential> credential = null;
private @Nullable ConnectionString connectionString;
private @Nullable String replicaSet = null;

private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_EXCEPTION_TRANSLATOR;
private PersistenceExceptionTranslator exceptionTranslator = MongoExceptionTranslator.DEFAULT_EXCEPTION_TRANSLATOR;

/**
* Set the {@link MongoClientSettings} to be used when creating {@link MongoClient}.
Expand Down Expand Up @@ -116,23 +114,34 @@ public void setReplicaSet(@Nullable String replicaSet) {
* @param exceptionTranslator
*/
public void setExceptionTranslator(@Nullable PersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator == null ? DEFAULT_EXCEPTION_TRANSLATOR : exceptionTranslator;
}

public Class<? extends MongoClient> getObjectType() {
return MongoClient.class;
this.exceptionTranslator = exceptionTranslator == null ? MongoExceptionTranslator.DEFAULT_EXCEPTION_TRANSLATOR
: exceptionTranslator;
}

@Override
@Nullable
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}

@Override
public Class<? extends MongoClient> getObjectType() {
return MongoClient.class;
}

@Override
protected MongoClient createInstance() throws Exception {
return createMongoClient(computeClientSetting());
}

@Override
protected void destroyInstance(@Nullable MongoClient instance) throws Exception {

if (instance != null) {
instance.close();
}
}

/**
* Create {@link MongoClientSettings} based on configuration and priority (lower is better).
* <ol>
Expand Down Expand Up @@ -324,14 +333,6 @@ private <T> T computeSettingsValue(T defaultValue, T fromSettings, T fromConnect
return !fromConnectionStringIsDefault ? fromConnectionString : defaultValue;
}

@Override
protected void destroyInstance(@Nullable MongoClient instance) throws Exception {

if (instance != null) {
instance.close();
}
}

private MongoClient createMongoClient(MongoClientSettings settings) throws UnknownHostException {
return MongoClients.create(settings, SpringDataMongoDB.driverInformation());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@

/**
* Common base class for usage with both {@link com.mongodb.client.MongoClients} defining common properties such as
* database name and exception translator.
* <br />
* database name and exception translator. <br />
* Not intended to be used directly.
*
* @author Christoph Strobl
Expand All @@ -47,8 +46,8 @@ public abstract class MongoDatabaseFactorySupport<C> implements MongoDatabaseFac
private final C mongoClient;
private final String databaseName;
private final boolean mongoInstanceCreated;
private final PersistenceExceptionTranslator exceptionTranslator;

private PersistenceExceptionTranslator exceptionTranslator;
private @Nullable WriteConcern writeConcern;

/**
Expand All @@ -75,15 +74,31 @@ protected MongoDatabaseFactorySupport(C mongoClient, String databaseName, boolea
this.exceptionTranslator = exceptionTranslator;
}

/**
* Configures the {@link PersistenceExceptionTranslator} to be used.
*
* @param exceptionTranslator the exception translator to set.
* @since 4.4
*/
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator;
}

@Override
public PersistenceExceptionTranslator getExceptionTranslator() {
return this.exceptionTranslator;
}

/**
* Configures the {@link WriteConcern} to be used on the {@link MongoDatabase} instance being created.
*
* @param writeConcern the writeConcern to set
* @param writeConcern the writeConcern to set.
*/
public void setWriteConcern(WriteConcern writeConcern) {
this.writeConcern = writeConcern;
}

@Override
public MongoDatabase getMongoDatabase() throws DataAccessException {
return getMongoDatabase(getDefaultDatabaseName());
}
Expand Down Expand Up @@ -116,10 +131,7 @@ public void destroy() throws Exception {
}
}

public PersistenceExceptionTranslator getExceptionTranslator() {
return this.exceptionTranslator;
}

@Override
public MongoDatabaseFactory withSession(ClientSession session) {
return new MongoDatabaseFactorySupport.ClientSessionBoundMongoDbFactory(session, this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,17 @@
import java.util.Set;

import org.bson.BsonInvalidOperationException;

import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.PermissionDeniedDataAccessException;
import org.springframework.dao.TransientDataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.mongodb.ClientSessionException;
import org.springframework.data.mongodb.TransientClientSessionException;
import org.springframework.data.mongodb.TransientMongoDbException;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
import org.springframework.data.mongodb.util.MongoDbErrorCodes;
import org.springframework.lang.Nullable;
Expand All @@ -53,6 +52,8 @@
*/
public class MongoExceptionTranslator implements PersistenceExceptionTranslator {

public static final MongoExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();

private static final Set<String> DUPLICATE_KEY_EXCEPTIONS = Set.of("MongoException.DuplicateKey",
"DuplicateKeyException");

Expand All @@ -70,18 +71,7 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
@Override
@Nullable
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {

DataAccessException translatedException = doTranslateException(ex);
if (translatedException == null) {
return null;
}

// Translated exceptions that per se are not be recoverable (eg. WriteConflicts), might still be transient inside a
// transaction. Let's wrap those.
return (isTransientFailure(ex) && !(translatedException instanceof TransientDataAccessException))
? new TransientMongoDbException(ex.getMessage(), translatedException)
: translatedException;

return doTranslateException(ex);
}

@Nullable
Expand Down Expand Up @@ -180,21 +170,23 @@ DataAccessException doTranslateException(RuntimeException ex) {
/**
* Check if a given exception holds an error label indicating a transient failure.
*
* @param e
* @param e the exception to inspect.
* @return {@literal true} if the given {@link Exception} is a {@link MongoException} holding one of the transient
* exception error labels.
* @see MongoException#hasErrorLabel(String)
* @since 3.3
* @since 4.4
*/
public static boolean isTransientFailure(Exception e) {
public boolean isTransientFailure(Exception e) {

if (!(e instanceof MongoException)) {
return false;
if (e instanceof MongoException mongoException) {
return mongoException.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL)
|| mongoException.hasErrorLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL);
}

MongoException mongoException = (MongoException) e;
if (e.getCause() != e && e.getCause() instanceof Exception ex) {
return isTransientFailure(ex);
}

return mongoException.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL)
|| mongoException.hasErrorLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL);
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@
public class ReactiveMongoClientFactoryBean extends AbstractFactoryBean<MongoClient>
implements PersistenceExceptionTranslator {

private static final PersistenceExceptionTranslator DEFAULT_EXCEPTION_TRANSLATOR = new MongoExceptionTranslator();

private @Nullable String connectionString;
private @Nullable String host;
private @Nullable Integer port;
private @Nullable MongoClientSettings mongoClientSettings;
private PersistenceExceptionTranslator exceptionTranslator = DEFAULT_EXCEPTION_TRANSLATOR;
private PersistenceExceptionTranslator exceptionTranslator = MongoExceptionTranslator.DEFAULT_EXCEPTION_TRANSLATOR;

/**
* Configures the host to connect to.
Expand Down Expand Up @@ -86,7 +84,13 @@ public void setMongoClientSettings(@Nullable MongoClientSettings mongoClientSett
* @param exceptionTranslator
*/
public void setExceptionTranslator(@Nullable PersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator == null ? DEFAULT_EXCEPTION_TRANSLATOR : exceptionTranslator;
this.exceptionTranslator = exceptionTranslator == null ? MongoExceptionTranslator.DEFAULT_EXCEPTION_TRANSLATOR
: exceptionTranslator;
}

@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}

@Override
Expand Down Expand Up @@ -123,8 +127,4 @@ protected void destroyInstance(@Nullable MongoClient instance) throws Exception
instance.close();
}

@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return exceptionTranslator.translateExceptionIfPossible(ex);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public SimpleMongoClientDatabaseFactory(MongoClient mongoClient, String database
* @param mongoInstanceCreated
*/
SimpleMongoClientDatabaseFactory(MongoClient mongoClient, String databaseName, boolean mongoInstanceCreated) {
super(mongoClient, databaseName, mongoInstanceCreated, new MongoExceptionTranslator());
super(mongoClient, databaseName, mongoInstanceCreated, MongoExceptionTranslator.DEFAULT_EXCEPTION_TRANSLATOR);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ public class SimpleReactiveMongoDatabaseFactory implements DisposableBean, React
private final String databaseName;
private final boolean mongoInstanceCreated;

private final PersistenceExceptionTranslator exceptionTranslator;

private PersistenceExceptionTranslator exceptionTranslator = MongoExceptionTranslator.DEFAULT_EXCEPTION_TRANSLATOR;
private @Nullable WriteConcern writeConcern;

/**
Expand Down Expand Up @@ -85,7 +84,21 @@ private SimpleReactiveMongoDatabaseFactory(MongoClient client, String databaseNa
this.mongo = client;
this.databaseName = databaseName;
this.mongoInstanceCreated = mongoInstanceCreated;
this.exceptionTranslator = new MongoExceptionTranslator();
}

/**
* Configures the {@link PersistenceExceptionTranslator} to be used.
*
* @param exceptionTranslator the exception translator to set.
* @since 4.4
*/
public void setExceptionTranslator(PersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator;
}

@Override
public PersistenceExceptionTranslator getExceptionTranslator() {
return this.exceptionTranslator;
}

/**
Expand All @@ -97,10 +110,12 @@ public void setWriteConcern(WriteConcern writeConcern) {
this.writeConcern = writeConcern;
}

@Override
public Mono<MongoDatabase> getMongoDatabase() throws DataAccessException {
return getMongoDatabase(databaseName);
}

@Override
public Mono<MongoDatabase> getMongoDatabase(String dbName) throws DataAccessException {

Assert.hasText(dbName, "Database name must not be empty");
Expand All @@ -118,17 +133,14 @@ public Mono<MongoDatabase> getMongoDatabase(String dbName) throws DataAccessExce
*
* @see DisposableBean#destroy()
*/
@Override
public void destroy() throws Exception {

if (mongoInstanceCreated) {
mongo.close();
}
}

public PersistenceExceptionTranslator getExceptionTranslator() {
return this.exceptionTranslator;
}

@Override
public CodecRegistry getCodecRegistry() {
return this.mongo.getDatabase(databaseName).getCodecRegistry();
Expand Down
Loading

0 comments on commit 7fbd496

Please sign in to comment.