Package org.ow2.easybeans.transaction.interceptors

Source Code of org.ow2.easybeans.transaction.interceptors.AbsTransactionInterceptor

/**
* EasyBeans
* Copyright (C) 2006 Bull S.A.S.
* Contact: easybeans@ow2.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
* USA
*
* --------------------------------------------------------------------------
* $Id: AbsTransactionInterceptor.java 5369 2010-02-24 14:58:19Z benoitf $
* --------------------------------------------------------------------------
*/

package org.ow2.easybeans.transaction.interceptors;

import static javax.transaction.Status.STATUS_MARKED_ROLLBACK;

import java.lang.reflect.Method;
import java.util.Map;

import javax.ejb.ApplicationException;
import javax.ejb.EJBException;
import javax.ejb.EJBTransactionRolledbackException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

import org.ow2.easybeans.api.EasyBeansInterceptor;
import org.ow2.easybeans.api.EasyBeansInvocationContext;
import org.ow2.easybeans.api.Factory;
import org.ow2.easybeans.api.bean.EasyBeansSFSB;
import org.ow2.easybeans.transaction.JTransactionManager;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;
import org.ow2.util.pool.api.Pool;
import org.ow2.util.pool.api.PoolException;

/**
* Defines an abstract interceptor for transaction with common code used by all
* transaction interceptors.
* @author Florent Benoit
*/
public abstract class AbsTransactionInterceptor implements EasyBeansInterceptor {

    /**
     * Logger.
     */
    private Log logger = LogFactory.getLog(AbsTransactionInterceptor.class);

    /**
     * Transaction manager.
     */
    private TransactionManager transactionManager = null;

    /**
     * Constructor.<br>
     * Acquire the transaction manager.
     */
    public AbsTransactionInterceptor() {
        this.transactionManager = JTransactionManager.getTransactionManager();
    }

    /**
     * Defines the code used by the transaction interceptor on a given method.
     * @param invocationContext context with useful attributes on the current
     *        invocation
     * @return result of the next invocation (to chain interceptors)
     * @throws Exception if interceptor fails
     */
    public abstract Object intercept(final EasyBeansInvocationContext invocationContext) throws Exception;

    /**
     * Gets the transaction manager.
     * @return TM.
     */
    public TransactionManager getTransactionManager() {
        return transactionManager;
    }

    /**
     * Gets the application exception (if any) for the given invocation context
     * and the given exception.<br />
     * Note that a checked Exception is by default an application exception.
     * @param invocationContext context that provides access to the Method
     *        object.
     * @param e the exception to check
     * @return the application exception object, else null.
     */
    protected ApplicationException getApplicationException(final EasyBeansInvocationContext invocationContext,
            final Exception e) {
        Map<String, ApplicationException> applicationExceptions = invocationContext.getFactory().getBeanInfo()
                .getApplicationExceptions();
        ApplicationException appException = applicationExceptions.get(e.getClass().getName());
        if (appException != null) {
            return appException;
        }
        // If runtime exception, not an application by default
        if (e instanceof RuntimeException) {
            return null;
        }
        // Is it a checked Exception ?
        Method method = invocationContext.getMethod();
        if (method != null) {
            Class<?>[] exceptions = method.getExceptionTypes();
            if (exceptions != null) {
                for (Class<?> clazz : exceptions) {
                    // Is an Exception but not a runtime exception
                    if (clazz.isInstance(e) && !(e instanceof RuntimeException)) {
                        // Checked exception, so application exception with
                        // rollback = false (default)
                        return applicationExceptions.get("DEFAULT");
                    }
                }
            }
        }
        // Was not a checked exception.
        return null;

    }

    /**
     * Remove from the factory's pool the bean found in the current invocation
     * context.
     * @param invocationContext the context of the current invocation
     * @throws PoolException if removal is failing
     */
    @SuppressWarnings("unchecked")
    protected void discard(final EasyBeansInvocationContext invocationContext) throws PoolException {

        Object target = invocationContext.getTarget();

        // factory is a stateful factory ?
        if (target instanceof EasyBeansSFSB) {
            // Gets the factory
            Factory factory = invocationContext.getFactory();

            // get pool
            Pool<EasyBeansSFSB, Long> pool = factory.getPool();

            // Bean is a stateful bean
            EasyBeansSFSB bean = (EasyBeansSFSB) invocationContext.getTarget();

            // discard instance
            pool.discard(bean);
        } else {
            logger.debug("Instance not discarded as it is not a stateful bean");
        }

    }

    /**
     * Marks the transaction for rollback.
     */
    protected void markTransactionRollback() {
        // Look if there is a transaction
        Transaction transaction;
        try {
            transaction = getTransactionManager().getTransaction();
        } catch (SystemException se) {
            throw new EJBException("Cannot get the current transaction on transaction manager.", se);
        }
        if (transaction != null) {
            try {
                transactionManager.setRollbackOnly();
            } catch (IllegalStateException e) {
                logger.warn("Cannot mark transaction as rollbackOnly", e);
            } catch (SystemException e) {
                logger.warn("Cannot mark transaction as rollbackOnly", e);
            }
        }
    }

    /**
     * Test if current transaction is with status STATUS_MARKED_ROLLBACK.
     * @return true if status == STATUS_MARKED_ROLLBACK
     */
    protected boolean isMarkedRollbackOnly() {
        try {
            return (STATUS_MARKED_ROLLBACK == transactionManager.getStatus());
        } catch (SystemException e) {
            logger.warn("Cannot get transaction status", e);
            return false;
        }
    }

    /**
     * Rollback the current transaction.
     */
    protected void rollback() {
        try {
            transactionManager.rollback();
        } catch (IllegalStateException e) {
            logger.warn("Cannot rollback the transaction", e);
        } catch (SecurityException e) {
            logger.warn("Cannot rollback the transaction", e);
        } catch (SystemException e) {
            logger.warn("Cannot rollback the transaction", e);
        }
    }

    /**
     * Commit the current transaction.
     */
    protected void commit() {
        try {
            transactionManager.commit();
        } catch (IllegalStateException e) {
            logger.warn("Cannot commit the transaction", e);
        } catch (SecurityException e) {
            logger.warn("Cannot commit the transaction", e);
        } catch (HeuristicMixedException e) {
            logger.warn("Cannot commit the transaction", e);
        } catch (HeuristicRollbackException e) {
            logger.warn("Cannot commit the transaction", e);
        } catch (RollbackException e) {
            logger.warn("Cannot commit the transaction", e);
        } catch (SystemException e) {
            logger.warn("Cannot commit the transaction", e);
        }
    }

    /**
     * Handle an exception for bean managed transaction.<br />
     * See Chapter 14.3.1.
     * @param invocationContext the context of the current invocation
     * @param e the exception to handle
     * @throws Exception when handling the exception.
     */
    protected void handleBeanManagedException(final EasyBeansInvocationContext invocationContext, final Exception e)
            throws Exception {
        ApplicationException applicationException = getApplicationException(invocationContext, e);

        // it is an application exception
        if (applicationException != null) {
            // Re-throw AppException.
            throw e;
        }

        // else, not an application exception :

        // Log the exception or error.
        logger.error("Bean Managed Transaction : Exception (not application exception) in business method", e);

        // Mark for rollback a transaction that has been
        // started, but not yet completed, by the instance.
        markTransactionRollback();

        // Discard instance.
        try {
            discard(invocationContext);
        } catch (PoolException pe) {
            throw new EJBException("Cannot discard the bean", pe);
        }

        // Throw EJBException to client.
        throw new EJBException("Bean Managed Transaction : Business exception which is not an application exception", e);
    }

    /**
     * Handle an exception that are in an unspecified transaction context.<br />
     * See Chapter 14.3.1.
     * @param invocationContext the context of the current invocation
     * @param e the exception to handle
     * @throws Exception when handling the exception.
     */
    protected void handleUnspecifiedTransactionContext(final EasyBeansInvocationContext invocationContext,
            final Exception e) throws Exception {

        ApplicationException applicationException = getApplicationException(invocationContext, e);

        // it is an application exception
        if (applicationException != null) {
            // Re-throw AppException.
            throw e;
        }

        // else, not an application exception :

        // Log the exception or error.
        logger.error("Exception (not application exception) in business method", e);

        // Discard instance.
        try {
            discard(invocationContext);
        } catch (PoolException pe) {
            throw new EJBException("Cannot discard the bean", pe);
        }

        // Throw EJBException to client.
        throw new EJBException("Business exception which is not an application exception", e);

    }

    /**
     * Handle an exception and the transaction is the client transaction.<br />
     * See Chapter 14.3.1.
     * @param invocationContext the context of the current invocation
     * @param e the exception to handle
     * @throws Exception when handling the exception.
     */
    protected void handleContextClientTransaction(final EasyBeansInvocationContext invocationContext, final Exception e)
            throws Exception {
        ApplicationException applicationException = getApplicationException(invocationContext, e);

        // An application exception ?
        if (applicationException != null) {
            /*
             * Re-throw AppException. Mark the transaction for rollback if the
             * application exception is specified as causing rollback.
             */

            // Mark the transaction for rollback.
            if (applicationException.rollback()) {
                markTransactionRollback();
            }

            // rethrow
            throw e;
        }

        // else, not an application exception :

        // Log the exception or error.
        logger.error("Exception (not application exception) in business method", e);

        // Mark the transaction for rollback.
        markTransactionRollback();

        // Discard instance.
        try {
            discard(invocationContext);
        } catch (PoolException pe) {
            throw new EJBException("Cannot discard the bean", pe);
        }

        // Throw javax.ejb.EJBTransactionRolledbackException to
        // client.
        EJBTransactionRolledbackException transactionException = new EJBTransactionRolledbackException(
                "System exception, The transaction has been marked for rollback only");
        transactionException.initCause(e);
        throw transactionException;
    }

    /**
     * Handle an exception and the transaction is the container transaction.
     * Bean method runs in the context of a transaction that the container
     * started immediately before dispatching the business method.<br />
     * See Chapter 14.3.1.
     * @param invocationContext the context of the current invocation
     * @param e the exception to handle
     * @throws Exception when handling the exception.
     */
    protected void handleContextContainerTransaction(final EasyBeansInvocationContext invocationContext,
            final Exception e) throws Exception {

        ApplicationException applicationException = getApplicationException(invocationContext, e);

        // An application exception ?
        if (applicationException != null) {
            /*
             * If the instance called setRollback-Only(), then rollback the
             * transaction, and re-throw AppException.
             */
            if (isMarkedRollbackOnly()) {
                rollback();
                throw e;
            }

            /*
             * Mark the transaction for rollback if the application exception is
             * specified as causing rollback, and then re-throw AppException.
             * Otherwise, attempt to commit the transaction, and then re-throw
             * AppException.
             */
            if (applicationException.rollback()) {
                // TODO: rollback or mark rollback ??
                rollback();
            } else {
                commit();
            }
            throw e;
        }
        // else, not an application exception :
        // Log the exception or error.
        logger.error("Exception (not application exception) in business method", e);

        // Rollback the container-started transaction.
        rollback();

        // Discard instance.
        try {
            discard(invocationContext);
        } catch (PoolException pe) {
            throw new EJBException("Cannot discard the bean", pe);
        }

        // Throw EJBException to client.
        throw new EJBException("Exception in a business interface with REQUIRED TX attribute", e);

    }
}
TOP

Related Classes of org.ow2.easybeans.transaction.interceptors.AbsTransactionInterceptor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.