use of cn.taketoday.transaction.TransactionException in project today-infrastructure by TAKETODAY.
the class AbstractReactiveTransactionManager method getReactiveTransaction.
// ---------------------------------------------------------------------
// Implementation of ReactiveTransactionManager
// ---------------------------------------------------------------------
/**
* This implementation handles propagation behavior. Delegates to
* {@code doGetTransaction}, {@code isExistingTransaction}
* and {@code doBegin}.
*
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
*/
@Override
public final Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
return TransactionSynchronizationManager.forCurrentTransaction().flatMap(synchronizationManager -> {
Object transaction = doGetTransaction(synchronizationManager);
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(synchronizationManager, def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
return Mono.error(new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout()));
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
return Mono.error(new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'"));
} else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
return TransactionContextManager.currentContext().map(TransactionSynchronizationManager::new).flatMap(nestedSynchronizationManager -> suspend(nestedSynchronizationManager, null).map(Optional::of).defaultIfEmpty(Optional.empty()).flatMap(suspendedResources -> {
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
return Mono.defer(() -> {
GenericReactiveTransaction status = newReactiveTransaction(nestedSynchronizationManager, def, transaction, true, debugEnabled, suspendedResources.orElse(null));
return doBegin(nestedSynchronizationManager, transaction, def).doOnSuccess(ignore -> prepareSynchronization(nestedSynchronizationManager, status, def)).thenReturn(status);
}).onErrorResume(ErrorPredicates.RUNTIME_OR_ERROR, ex -> resume(nestedSynchronizationManager, null, suspendedResources.orElse(null)).then(Mono.error(ex)));
}));
} else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " + "isolation level will effectively be ignored: " + def);
}
return Mono.just(prepareReactiveTransaction(synchronizationManager, def, null, true, debugEnabled, null));
}
});
}
use of cn.taketoday.transaction.TransactionException in project today-infrastructure by TAKETODAY.
the class BeanFactoryTransactionTests method doTestGetsAreNotTransactional.
private void doTestGetsAreNotTransactional(final ITestBean testBean) {
// Install facade
PlatformTransactionManager ptm = mock(PlatformTransactionManager.class);
PlatformTransactionManagerFacade.delegate = ptm;
assertThat(testBean.getAge() == 666).as("Age should not be " + testBean.getAge()).isTrue();
// Expect no methods
verifyNoInteractions(ptm);
// Install facade expecting a call
final TransactionStatus ts = mock(TransactionStatus.class);
ptm = new PlatformTransactionManager() {
private boolean invoked;
@Override
public TransactionStatus getTransaction(@Nullable TransactionDefinition def) throws TransactionException {
if (invoked) {
throw new IllegalStateException("getTransaction should not get invoked more than once");
}
invoked = true;
if (!(def.getName().contains(DerivedTestBean.class.getName()) && def.getName().contains("setAge"))) {
throw new IllegalStateException("transaction name should contain class and method name: " + def.getName());
}
return ts;
}
@Override
public void commit(TransactionStatus status) throws TransactionException {
assertThat(status == ts).isTrue();
}
@Override
public void rollback(TransactionStatus status) throws TransactionException {
throw new IllegalStateException("rollback should not get invoked");
}
};
PlatformTransactionManagerFacade.delegate = ptm;
// TODO same as old age to avoid ordering effect for now
int age = 666;
testBean.setAge(age);
assertThat(testBean.getAge() == age).isTrue();
}
use of cn.taketoday.transaction.TransactionException in project today-framework by TAKETODAY.
the class BeanFactoryTransactionTests method doTestGetsAreNotTransactional.
private void doTestGetsAreNotTransactional(final ITestBean testBean) {
// Install facade
PlatformTransactionManager ptm = mock(PlatformTransactionManager.class);
PlatformTransactionManagerFacade.delegate = ptm;
assertThat(testBean.getAge() == 666).as("Age should not be " + testBean.getAge()).isTrue();
// Expect no methods
verifyNoInteractions(ptm);
// Install facade expecting a call
final TransactionStatus ts = mock(TransactionStatus.class);
ptm = new PlatformTransactionManager() {
private boolean invoked;
@Override
public TransactionStatus getTransaction(@Nullable TransactionDefinition def) throws TransactionException {
if (invoked) {
throw new IllegalStateException("getTransaction should not get invoked more than once");
}
invoked = true;
if (!(def.getName().contains(DerivedTestBean.class.getName()) && def.getName().contains("setAge"))) {
throw new IllegalStateException("transaction name should contain class and method name: " + def.getName());
}
return ts;
}
@Override
public void commit(TransactionStatus status) throws TransactionException {
assertThat(status == ts).isTrue();
}
@Override
public void rollback(TransactionStatus status) throws TransactionException {
throw new IllegalStateException("rollback should not get invoked");
}
};
PlatformTransactionManagerFacade.delegate = ptm;
// TODO same as old age to avoid ordering effect for now
int age = 666;
testBean.setAge(age);
assertThat(testBean.getAge() == age).isTrue();
}
use of cn.taketoday.transaction.TransactionException in project today-framework by TAKETODAY.
the class AbstractReactiveTransactionManager method processCommit.
/**
* Process an actual commit.
* Rollback-only flags have already been checked and applied.
*
* @param synchronizationManager the synchronization manager bound to the current transaction
* @param status object representing the transaction
* @throws TransactionException in case of commit failure
*/
private Mono<Void> processCommit(TransactionSynchronizationManager synchronizationManager, GenericReactiveTransaction status) throws TransactionException {
AtomicBoolean beforeCompletionInvoked = new AtomicBoolean();
Mono<Object> commit = prepareForCommit(synchronizationManager, status).then(triggerBeforeCommit(synchronizationManager, status)).then(triggerBeforeCompletion(synchronizationManager, status)).then(Mono.defer(() -> {
beforeCompletionInvoked.set(true);
if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
return doCommit(synchronizationManager, status);
}
return Mono.empty();
})).then(Mono.empty().onErrorResume(ex -> {
Mono<Object> propagateException = Mono.error(ex);
// Store result in a local variable in order to appease the
// Eclipse compiler with regard to inferred generics.
Mono<Object> result = propagateException;
if (ErrorPredicates.UNEXPECTED_ROLLBACK.test(ex)) {
result = triggerAfterCompletion(synchronizationManager, status, TransactionSynchronization.STATUS_ROLLED_BACK).then(propagateException);
} else if (ErrorPredicates.TRANSACTION_EXCEPTION.test(ex)) {
result = triggerAfterCompletion(synchronizationManager, status, TransactionSynchronization.STATUS_UNKNOWN).then(propagateException);
} else if (ErrorPredicates.RUNTIME_OR_ERROR.test(ex)) {
Mono<Void> mono;
if (!beforeCompletionInvoked.get()) {
mono = triggerBeforeCompletion(synchronizationManager, status);
} else {
mono = Mono.empty();
}
result = mono.then(doRollbackOnCommitException(synchronizationManager, status, ex)).then(propagateException);
}
return result;
})).then(Mono.defer(() -> triggerAfterCommit(synchronizationManager, status).onErrorResume(ex -> triggerAfterCompletion(synchronizationManager, status, TransactionSynchronization.STATUS_COMMITTED).then(Mono.error(ex))).then(triggerAfterCompletion(synchronizationManager, status, TransactionSynchronization.STATUS_COMMITTED))));
return commit.onErrorResume(ex -> cleanupAfterCompletion(synchronizationManager, status).then(Mono.error(ex))).then(cleanupAfterCompletion(synchronizationManager, status));
}
use of cn.taketoday.transaction.TransactionException in project today-framework by TAKETODAY.
the class AbstractReactiveTransactionManager method getReactiveTransaction.
// ---------------------------------------------------------------------
// Implementation of ReactiveTransactionManager
// ---------------------------------------------------------------------
/**
* This implementation handles propagation behavior. Delegates to
* {@code doGetTransaction}, {@code isExistingTransaction}
* and {@code doBegin}.
*
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
*/
@Override
public final Mono<ReactiveTransaction> getReactiveTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
return TransactionSynchronizationManager.forCurrentTransaction().flatMap(synchronizationManager -> {
Object transaction = doGetTransaction(synchronizationManager);
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(synchronizationManager, def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
return Mono.error(new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout()));
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
return Mono.error(new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'"));
} else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
return TransactionContextManager.currentContext().map(TransactionSynchronizationManager::new).flatMap(nestedSynchronizationManager -> suspend(nestedSynchronizationManager, null).map(Optional::of).defaultIfEmpty(Optional.empty()).flatMap(suspendedResources -> {
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
return Mono.defer(() -> {
GenericReactiveTransaction status = newReactiveTransaction(nestedSynchronizationManager, def, transaction, true, debugEnabled, suspendedResources.orElse(null));
return doBegin(nestedSynchronizationManager, transaction, def).doOnSuccess(ignore -> prepareSynchronization(nestedSynchronizationManager, status, def)).thenReturn(status);
}).onErrorResume(ErrorPredicates.RUNTIME_OR_ERROR, ex -> resume(nestedSynchronizationManager, null, suspendedResources.orElse(null)).then(Mono.error(ex)));
}));
} else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " + "isolation level will effectively be ignored: " + def);
}
return Mono.just(prepareReactiveTransaction(synchronizationManager, def, null, true, debugEnabled, null));
}
});
}
Aggregations