package org.springframework.data.mongodb.tx; import com.mongodb.ReadPreference; import com.mongodb.WriteConcern; import org.apache.commons.lang.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.aop.framework.AopProxyUtils; import org.springframework.aop.support.AopUtils; import org.springframework.stereotype.Component; import java.lang.reflect.Method; @Aspect @Component public class MongoTxAspect { @Around("@annotation(org.springframework.data.mongodb.tx.MongoTx)") public Object executeWithinMongoTx(final ProceedingJoinPoint pjp) throws Throwable { if (MongoTxConfigHolder.get() != null) { //someone earlier in the call chain sets a mongo tx config so leave it as is and proceed return pjp.proceed(); } else { try { //we are the outermost around aspect so configure mongo tx final MongoTx mongoTx = getMongoTxAnnotation(pjp); MongoTxConfigHolder.registerConfig(configFromAnnotation(mongoTx)); return pjp.proceed(); } finally { MongoTxConfigHolder.resetConfig(); } } } private MongoTx getMongoTxAnnotation(ProceedingJoinPoint pjp) { final Class<?> targetClass = AopProxyUtils.ultimateTargetClass(pjp.getTarget()); final MethodSignature signature = (MethodSignature) pjp.getSignature(); final Method mostSpecificMethod = AopUtils.getMostSpecificMethod(signature.getMethod(), targetClass); final MongoTx mongoTxAnnotation = mostSpecificMethod.getAnnotation(MongoTx.class); if (mongoTxAnnotation == null) { throw new IllegalStateException( String.format("cannot determine MongoTx annotation in %s with found target class %s and method %s.", pjp, targetClass, mostSpecificMethod)); } return mongoTxAnnotation; } private MongoTxConfig configFromAnnotation(final MongoTx mongoTx) { ReadPreference readPreference = null; if (StringUtils.isNotBlank(mongoTx.readPreference())) { readPreference = ReadPreference.valueOf(mongoTx.readPreference()); } WriteConcern writeConcern = null; final String writeConcernStr = mongoTx.writeConcern(); if (StringUtils.isNotBlank(writeConcernStr) && !MongoTx.DEFAULT_WRITE_CONCERN.equals(writeConcernStr)) { writeConcern = WriteConcern.valueOf(writeConcernStr); if (writeConcern == null) { throw new IllegalArgumentException("writeConcern '" + writeConcernStr + "' not known"); } } return new MongoTxConfig(writeConcern, readPreference); } }