org.springmodules.workflow.jbpm30.JbpmSessionFactoryUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.springmodules.workflow.jbpm30.JbpmSessionFactoryUtils.java

Source

/*
 * Copyright 2002-2005 the original author or authors.
 *
 * 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 org.springmodules.workflow.jbpm30;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.jbpm.db.JbpmSession;
import org.jbpm.db.JbpmSessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;

/**
 * Helper class featuring methods for jBPM Session handling, allowing for reuse of jBPM Session instances within transactions.
 * As jBPM 3.0.x actually stands on top of Hibernate, this class will delegate as much as possible work to Spring Hibernate SessionFactoryUtils.
 * 
 * @author Rob Harrop
 */
public abstract class JbpmSessionFactoryUtils {

    private static final Log logger = LogFactory.getLog(JbpmSessionFactoryUtils.class);

    /**
     * Returns a jBPM session. It is aware of and will return the thread-bound session if one is found.
     * 
     * @param sessionFactory
     * @return
     */
    public static JbpmSession getSession(JbpmSessionFactory sessionFactory) {
        try {
            return doGetSession(sessionFactory, true);
        } catch (RuntimeException e) {
            throw new DataAccessResourceFailureException("Could not open jBPM Session", e);
        }
    }

    /**
     * Returns a jBPM session. It is aware of and will return the thread-bound session if one is found.
     * jBPM exceptions will not be translated.
     * 
     * @param sessionFactory
     * @param allowCreate
     * @return
     */
    public static JbpmSession doGetSession(JbpmSessionFactory sessionFactory, boolean allowCreate) {
        Assert.notNull(sessionFactory, "No JbpmSessionFactory specified");

        JbpmSessionHolder jbpmSessionHolder = (JbpmSessionHolder) TransactionSynchronizationManager
                .getResource(sessionFactory);

        if (jbpmSessionHolder != null && jbpmSessionHolder.getJbpmSession() != null) {
            return jbpmSessionHolder.getJbpmSession();
        }

        JbpmSession jbpmSession = sessionFactory.openJbpmSession();
        jbpmSessionHolder = new JbpmSessionHolder(jbpmSession);

        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            TransactionSynchronizationManager.registerSynchronization(
                    new SpringJbpmSessionSynchronization(jbpmSessionHolder, sessionFactory));
            TransactionSynchronizationManager.bindResource(sessionFactory, jbpmSessionHolder);
        }

        return jbpmSession;
    }

    /**
     * Releases the jBPM session.
     * 
     * @param jbpmSession
     * @param jbpmSessionFactory
     */
    public static void releaseSession(JbpmSession jbpmSession, JbpmSessionFactory jbpmSessionFactory) {
        if (jbpmSession == null)
            return;

        if (!isTransactional(jbpmSession, jbpmSessionFactory)) {
            logger.debug("Closing jBPM session");
            jbpmSession.close();
        }

    }

    /**
     * Return whether the given jBPM Session is transactional, that is,
     * bound to the current thread by Spring's transaction facilities.
     * 
     * @param jbpmSession
     * @param jbpmSessionFactory
     * @return
     */
    public static boolean isTransactional(JbpmSession jbpmSession, JbpmSessionFactory jbpmSessionFactory) {
        if (jbpmSessionFactory == null)
            return false;

        JbpmSessionHolder jbpmSessionHolder = (JbpmSessionHolder) TransactionSynchronizationManager
                .getResource(jbpmSessionFactory);
        return (jbpmSessionHolder != null && jbpmSessionHolder.getJbpmSession() == jbpmSession);
    }

    /**
     * Converts Jbpm RuntimeExceptions into Spring specific ones (if possible).
     * @param ex
     * @return
     */
    public static RuntimeException convertJbpmException(RuntimeException ex) {
        // try to decode and translate HibernateExceptions
        if (ex instanceof HibernateException) {
            return SessionFactoryUtils.convertHibernateAccessException((HibernateException) ex);
        }

        if (ex.getCause() instanceof HibernateException) {
            DataAccessException rootCause = SessionFactoryUtils
                    .convertHibernateAccessException((HibernateException) ex.getCause());
            return new NestedDataAccessException(ex.getMessage(), rootCause);
        }

        // cannot convert the exception in any meaningful way
        return ex;
    }

    /**
     * Callback for resource cleanup at the end of a transaction (e.g.
     * when participating in a JtaTransactionManager transaction).
     * 
     * @see org.springframework.transaction.jta.JtaTransactionManager
     */
    private static class SpringJbpmSessionSynchronization extends TransactionSynchronizationAdapter {

        private static final Log logger = LogFactory.getLog(SpringJbpmSessionSynchronization.class);

        private JbpmSessionHolder jbpmSessionHolder;
        private JbpmSessionFactory jbpmSessionFactory;

        public SpringJbpmSessionSynchronization(JbpmSessionHolder jbpmSessionHolder,
                JbpmSessionFactory jbpmSessionFactory) {
            this.jbpmSessionHolder = jbpmSessionHolder;
            this.jbpmSessionFactory = jbpmSessionFactory;
        }

        public void suspend() {
            if (logger.isDebugEnabled())
                logger.debug("suspend synchronization for jbpmSessionFactory "
                        + System.identityHashCode(jbpmSessionFactory));
            TransactionSynchronizationManager.unbindResource(this.jbpmSessionFactory);
        }

        public void resume() {
            if (logger.isDebugEnabled())
                logger.debug("resume synchronization for jbpmSessionFactory "
                        + System.identityHashCode(jbpmSessionFactory));
            TransactionSynchronizationManager.bindResource(jbpmSessionFactory, jbpmSessionHolder);
        }

        public void beforeCompletion() {
            if (logger.isDebugEnabled())
                logger.debug("beforeCompletion synchronization for jbpmSessionFactory "
                        + System.identityHashCode(jbpmSessionFactory));

            TransactionSynchronizationManager.unbindResource(jbpmSessionFactory);
            releaseSession(this.jbpmSessionHolder.getJbpmSession(), this.jbpmSessionFactory);
            this.jbpmSessionHolder.clear();

        }
    }
}