All Downloads are FREE. Search and download functionalities are using the official Maven repository.

examples.database.transaction.PerTransactionMethodInterceptor Maven / Gradle / Ivy

/*
 * Copyright 2016-2017 Testify Project.
 *
 * 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 examples.database.transaction;

import java.lang.reflect.Method;
import java.util.Optional;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.transaction.Transactional;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.glassfish.hk2.extras.operation.OperationHandle;
import org.glassfish.hk2.extras.operation.OperationManager;
import org.jvnet.hk2.annotations.Service;

/**
 * A method interceptor that intercepts methods annotated with @Transactional.
 * This interceptor begins, commits, and rolls back the currently active entity
 * manager.
 *
 * @author saden
 */
@Service
public class PerTransactionMethodInterceptor implements MethodInterceptor {

    private final OperationManager operationManager;
    private final EntityManager entityManager;

    @Inject
    PerTransactionMethodInterceptor(OperationManager operationManager, EntityManager entityManager) {
        this.operationManager = operationManager;
        this.entityManager = entityManager;
    }

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        OperationHandle handler = getOperationHandle();

        EntityTransaction tx = entityManager.getTransaction();

        if (tx == null || tx.isActive()) {
            return methodInvocation.proceed();
        }

        Object result;

        try {
            tx.begin();
            result = methodInvocation.proceed();
        } catch (Exception e) {
            doRollbackOrCommit(methodInvocation, e, tx);

            handler.closeOperation();

            throw e;
        }

        try {
            if (tx.isActive()) {
                tx.commit();
            }
        } finally {
            handler.closeOperation();
        }

        return result;
    }

    private synchronized OperationHandle getOperationHandle() {
        OperationHandle handler = operationManager.getCurrentOperation(PerTransactionImpl.INSTANCE);

        if (handler == null) {
            handler = operationManager.createAndStartOperation(PerTransactionImpl.INSTANCE);
        }

        return handler;

    }

    private void doRollbackOrCommit(MethodInvocation methodInvocation, Exception e, EntityTransaction tx) {
        if (tx.getRollbackOnly()) {
            tx.rollback();

            return;
        }

        Optional result = getTransactional(methodInvocation);

        if (result.isPresent()) {
            Transactional transactional = result.get();
            boolean commit = true;

            for (Class rollbackOn : transactional.rollbackOn()) {
                if (rollbackOn.isInstance(e)) {
                    commit = false;

                    for (Class exceptOn : transactional.dontRollbackOn()) {
                        if (exceptOn.isInstance(e)) {
                            commit = true;
                            break;
                        }
                    }

                    if (!commit) {
                        tx.rollback();
                    }

                    break;
                }
            }

            if (commit && tx.isActive()) {
                tx.commit();
            }
        }
    }

    private Optional getTransactional(MethodInvocation methodInvocation) {
        Transactional transactional;
        Method method = methodInvocation.getMethod();

        transactional = method.getAnnotation(Transactional.class);

        if (transactional == null) {
            Class targetClass = methodInvocation.getThis().getClass();
            transactional = targetClass.getAnnotation(Transactional.class);
        }

        return Optional.ofNullable(transactional);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy