Search in sources :

Example 1 with KotlinInterceptedMethod

use of io.micronaut.aop.kotlin.KotlinInterceptedMethod in project micronaut-data by micronaut-projects.

the class TransactionalInterceptor method interceptKotlinSuspended.

private Object interceptKotlinSuspended(MethodInvocationContext<Object, Object> context, InterceptedMethod interceptedMethod, TransactionInvocation<?> transactionInvocation, TransactionAttribute definition) {
    KotlinInterceptedMethod kotlinInterceptedMethod = (KotlinInterceptedMethod) interceptedMethod;
    TransactionSynchronizationManager.TransactionSynchronizationState state = Objects.requireNonNull(coroutineTxHelper).setupTxState(kotlinInterceptedMethod);
    return TransactionSynchronizationManager.withState(state, () -> {
        final SynchronousTransactionManager<?> transactionManager = transactionInvocation.transactionManager;
        TransactionInfo<Object> transactionInfo = (TransactionInfo<Object>) createTransactionIfNecessary(transactionManager, definition, context.getExecutableMethod());
        CompletionStage<?> result;
        try {
            result = interceptedMethod.interceptResultAsCompletionStage();
        } catch (Exception e) {
            CompletableFuture<?> r = new CompletableFuture<>();
            r.completeExceptionally(e);
            result = r;
        }
        CompletableFuture<Object> newResult = new CompletableFuture<>();
        // Last step to complete the TX, we need to use `withState` to properly setup thread-locals for the TX manager
        result.whenComplete((o, throwable) -> TransactionSynchronizationManager.withState(state, () -> {
            if (throwable == null) {
                commitTransactionAfterReturning(transactionInfo);
                newResult.complete(o);
            } else {
                try {
                    completeTransactionAfterThrowing(transactionInfo, throwable);
                } catch (Exception e) {
                // Ignore rethrow
                }
                newResult.completeExceptionally(throwable);
            }
            cleanupTransactionInfo(transactionInfo);
            return null;
        }));
        return interceptedMethod.handleResult(newResult);
    });
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) TransactionSynchronizationManager(io.micronaut.transaction.support.TransactionSynchronizationManager) KotlinInterceptedMethod(io.micronaut.aop.kotlin.KotlinInterceptedMethod) NoTransactionException(io.micronaut.transaction.exceptions.NoTransactionException) ConfigurationException(io.micronaut.context.exceptions.ConfigurationException) TransactionSystemException(io.micronaut.transaction.exceptions.TransactionSystemException)

Example 2 with KotlinInterceptedMethod

use of io.micronaut.aop.kotlin.KotlinInterceptedMethod in project micronaut-data by micronaut-projects.

the class TransactionalInterceptor method intercept.

@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
    InterceptedMethod interceptedMethod = InterceptedMethod.of(context);
    boolean isKotlinSuspended = interceptedMethod instanceof KotlinInterceptedMethod;
    try {
        boolean isReactive = interceptedMethod.resultType() == InterceptedMethod.ResultType.PUBLISHER;
        boolean isAsync = interceptedMethod.resultType() == InterceptedMethod.ResultType.COMPLETION_STAGE;
        final TransactionInvocation<?> transactionInvocation = transactionInvocationMap.computeIfAbsent(context.getExecutableMethod(), executableMethod -> {
            final String qualifier = executableMethod.stringValue(TransactionalAdvice.class).orElse(null);
            ReactiveTransactionOperations<?> reactiveTransactionOperations = beanLocator.findBean(ReactiveTransactionOperations.class, qualifier != null ? Qualifiers.byName(qualifier) : null).orElse(null);
            if ((isReactive || isAsync) && !(isKotlinSuspended && reactiveTransactionOperations == null)) {
                if (isReactive && reactiveTransactionOperations == null) {
                    throw new ConfigurationException("No reactive transaction management has been configured. Ensure you have correctly configured a reactive capable transaction manager");
                } else {
                    final TransactionAttribute transactionAttribute = resolveTransactionDefinition(executableMethod);
                    return new TransactionInvocation(null, reactiveTransactionOperations, transactionAttribute);
                }
            } else {
                SynchronousTransactionManager<?> transactionManager = beanLocator.getBean(SynchronousTransactionManager.class, qualifier != null ? Qualifiers.byName(qualifier) : null);
                final TransactionAttribute transactionAttribute = resolveTransactionDefinition(executableMethod);
                return new TransactionInvocation<>(transactionManager, null, transactionAttribute);
            }
        });
        final TransactionAttribute definition = transactionInvocation.definition;
        switch(interceptedMethod.resultType()) {
            case PUBLISHER:
                return interceptedMethod.handleResult(transactionInvocation.reactiveTransactionOperations.withTransaction(definition, (status) -> {
                    context.setAttribute(ReactiveTransactionStatus.STATUS, status);
                    context.setAttribute(ReactiveTransactionStatus.ATTRIBUTE, definition);
                    return Publishers.convertPublisher(context.proceed(), Publisher.class);
                }));
            case COMPLETION_STAGE:
                if (transactionInvocation.reactiveTransactionOperations != null) {
                    return interceptedMethod.handleResult(interceptedMethod.interceptResult());
                } else {
                    if (isKotlinSuspended) {
                        return interceptKotlinSuspended(context, interceptedMethod, transactionInvocation, definition);
                    } else {
                        throw new ConfigurationException("Async return type doesn't support transactional execution.");
                    }
                }
            case SYNCHRONOUS:
                final SynchronousTransactionManager<?> transactionManager = transactionInvocation.transactionManager;
                final TransactionInfo transactionInfo = createTransactionIfNecessary(transactionManager, definition, context.getExecutableMethod());
                Object retVal;
                try {
                    retVal = context.proceed();
                } catch (Throwable ex) {
                    completeTransactionAfterThrowing(transactionInfo, ex);
                    throw ex;
                } finally {
                    cleanupTransactionInfo(transactionInfo);
                }
                commitTransactionAfterReturning(transactionInfo);
                return retVal;
            default:
                return interceptedMethod.unsupported();
        }
    } catch (Exception e) {
        return interceptedMethod.handleException(e);
    }
}
Also used : Publishers(io.micronaut.core.async.publisher.Publishers) LoggerFactory(org.slf4j.LoggerFactory) CompletableFuture(java.util.concurrent.CompletableFuture) InterceptedMethod(io.micronaut.aop.InterceptedMethod) ExecutableMethod(io.micronaut.inject.ExecutableMethod) NoTransactionException(io.micronaut.transaction.exceptions.NoTransactionException) MethodInterceptor(io.micronaut.aop.MethodInterceptor) Nullable(io.micronaut.core.annotation.Nullable) Duration(java.time.Duration) Map(java.util.Map) TransactionSynchronizationManager(io.micronaut.transaction.support.TransactionSynchronizationManager) BeanLocator(io.micronaut.context.BeanLocator) TransactionStatus(io.micronaut.transaction.TransactionStatus) KotlinInterceptedMethod(io.micronaut.aop.kotlin.KotlinInterceptedMethod) ConfigurationException(io.micronaut.context.exceptions.ConfigurationException) TransactionDefinition(io.micronaut.transaction.TransactionDefinition) TransactionalAdvice(io.micronaut.transaction.annotation.TransactionalAdvice) Logger(org.slf4j.Logger) Publisher(org.reactivestreams.Publisher) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Qualifiers(io.micronaut.inject.qualifiers.Qualifiers) Singleton(jakarta.inject.Singleton) ReactiveTransactionOperations(io.micronaut.transaction.reactive.ReactiveTransactionOperations) Objects(java.util.Objects) NonNull(io.micronaut.core.annotation.NonNull) CompletionStage(java.util.concurrent.CompletionStage) SynchronousTransactionManager(io.micronaut.transaction.SynchronousTransactionManager) ReactiveTransactionStatus(io.micronaut.transaction.reactive.ReactiveTransactionStatus) MethodInvocationContext(io.micronaut.aop.MethodInvocationContext) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) TransactionSystemException(io.micronaut.transaction.exceptions.TransactionSystemException) Inject(jakarta.inject.Inject) InterceptPhase(io.micronaut.aop.InterceptPhase) InterceptedMethod(io.micronaut.aop.InterceptedMethod) KotlinInterceptedMethod(io.micronaut.aop.kotlin.KotlinInterceptedMethod) Publisher(org.reactivestreams.Publisher) KotlinInterceptedMethod(io.micronaut.aop.kotlin.KotlinInterceptedMethod) ReactiveTransactionOperations(io.micronaut.transaction.reactive.ReactiveTransactionOperations) NoTransactionException(io.micronaut.transaction.exceptions.NoTransactionException) ConfigurationException(io.micronaut.context.exceptions.ConfigurationException) TransactionSystemException(io.micronaut.transaction.exceptions.TransactionSystemException) TransactionalAdvice(io.micronaut.transaction.annotation.TransactionalAdvice) ConfigurationException(io.micronaut.context.exceptions.ConfigurationException)

Aggregations

KotlinInterceptedMethod (io.micronaut.aop.kotlin.KotlinInterceptedMethod)2 ConfigurationException (io.micronaut.context.exceptions.ConfigurationException)2 NoTransactionException (io.micronaut.transaction.exceptions.NoTransactionException)2 TransactionSystemException (io.micronaut.transaction.exceptions.TransactionSystemException)2 TransactionSynchronizationManager (io.micronaut.transaction.support.TransactionSynchronizationManager)2 CompletableFuture (java.util.concurrent.CompletableFuture)2 InterceptPhase (io.micronaut.aop.InterceptPhase)1 InterceptedMethod (io.micronaut.aop.InterceptedMethod)1 MethodInterceptor (io.micronaut.aop.MethodInterceptor)1 MethodInvocationContext (io.micronaut.aop.MethodInvocationContext)1 BeanLocator (io.micronaut.context.BeanLocator)1 AnnotationValue (io.micronaut.core.annotation.AnnotationValue)1 NonNull (io.micronaut.core.annotation.NonNull)1 Nullable (io.micronaut.core.annotation.Nullable)1 Publishers (io.micronaut.core.async.publisher.Publishers)1 ExecutableMethod (io.micronaut.inject.ExecutableMethod)1 Qualifiers (io.micronaut.inject.qualifiers.Qualifiers)1 SynchronousTransactionManager (io.micronaut.transaction.SynchronousTransactionManager)1 TransactionDefinition (io.micronaut.transaction.TransactionDefinition)1 TransactionStatus (io.micronaut.transaction.TransactionStatus)1