org.springframework.orm.hibernate3.HibernateInterceptor 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.springframework.orm.hibernate3;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* This interceptor binds a new Hibernate Session to the thread before a method
* call, closing and removing it afterwards in case of any method outcome.
* If there already is a pre-bound Session (e.g. from HibernateTransactionManager,
* or from a surrounding Hibernate-intercepted method), the interceptor simply
* participates in it.
*
* Application code must retrieve a Hibernate Session via the
* SessionFactoryUtils.getSession
method, to be able to detect a
* thread-bound Session. It is preferable to use getSession
with
* allowCreate=false, if the code relies on the interceptor to provide proper
* Session handling. Typically, the code will look as follows:
*
*
* public void doHibernateAction() {
* Session session = SessionFactoryUtils.getSession(this.sessionFactory, false);
* try {
* ...
* }
* catch (HibernateException ex) {
* throw SessionFactoryUtils.convertHibernateAccessException(ex);
* }
* }
*
* Note that the application must care about handling HibernateExceptions itself,
* preferably via delegating to the SessionFactoryUtils.convertHibernateAccessException
* method that converts them to exceptions that are compatible with the
* org.springframework.dao
exception hierarchy (like HibernateTemplate does).
*
* Unfortunately, this interceptor cannot convert checked HibernateExceptions
* to unchecked dao ones automatically. The intercepted method would have to throw
* HibernateException to be able to achieve this - thus the caller would still have
* to catch or rethrow it, even if it will never be thrown if intercepted.
*
*
This class can be considered a declarative alternative to HibernateTemplate's
* callback approach. The advantages are:
*
* - no anonymous classes necessary for callback implementations;
*
- the possibility to throw any application exceptions from within data access code.
*
*
* The drawbacks are:
*
* - the dependency on interceptor configuration;
*
- the delegating try/catch blocks.
*
*
* @author Juergen Hoeller
* @since 1.2
* @see SessionFactoryUtils#getSession
* @see HibernateTransactionManager
* @see HibernateTemplate
*/
public class HibernateInterceptor extends HibernateAccessor implements MethodInterceptor {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Session session = getSession();
boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());
if (existingTransaction) {
logger.debug("Found thread-bound Session for HibernateInterceptor");
}
else {
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
}
FlushMode previousFlushMode = null;
try {
previousFlushMode = applyFlushMode(session, existingTransaction);
enableFilters(session);
Object retVal = methodInvocation.proceed();
flushIfNecessary(session, existingTransaction);
return retVal;
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
finally {
if (existingTransaction) {
logger.debug("Not closing pre-bound Hibernate Session after HibernateInterceptor");
disableFilters(session);
if (previousFlushMode != null) {
session.setFlushMode(previousFlushMode);
}
}
else {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
SessionFactoryUtils.releaseSession(session, getSessionFactory());
}
}
}
/**
* Return a Session for use by this interceptor.
* @see SessionFactoryUtils#getSession
*/
protected Session getSession() {
return SessionFactoryUtils.getSession(
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
}
}