org.springmodules.workflow.jbpm30.JbpmSessionFactoryUtils Maven / Gradle / Ivy
/*
* 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();
}
}
}