001/* 002 * Copyright 2002-2014 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.orm.hibernate3; 018 019import org.aopalliance.intercept.MethodInterceptor; 020import org.aopalliance.intercept.MethodInvocation; 021import org.hibernate.FlushMode; 022import org.hibernate.HibernateException; 023import org.hibernate.Session; 024 025import org.springframework.transaction.support.TransactionSynchronizationManager; 026 027/** 028 * This interceptor binds a new Hibernate Session to the thread before a method 029 * call, closing and removing it afterwards in case of any method outcome. 030 * If there already is a pre-bound Session (e.g. from HibernateTransactionManager, 031 * or from a surrounding Hibernate-intercepted method), the interceptor simply 032 * participates in it. 033 * 034 * <p>Application code must retrieve a Hibernate Session via the 035 * {@code SessionFactoryUtils.getSession} method or - preferably - 036 * Hibernate's own {@code SessionFactory.getCurrentSession()} method, to be 037 * able to detect a thread-bound Session. Typically, the code will look like as follows: 038 * 039 * <pre class="code"> 040 * public void doSomeDataAccessAction() { 041 * Session session = this.sessionFactory.getCurrentSession(); 042 * ... 043 * // No need to close the Session or translate exceptions! 044 * }</pre> 045 * 046 * Note that this interceptor automatically translates HibernateExceptions, 047 * via delegating to the {@code SessionFactoryUtils.convertHibernateAccessException} 048 * method that converts them to exceptions that are compatible with the 049 * {@code org.springframework.dao} exception hierarchy (like HibernateTemplate does). 050 * This can be turned off if the raw exceptions are preferred. 051 * 052 * <p>This class can be considered a declarative alternative to HibernateTemplate's 053 * callback approach. The advantages are: 054 * <ul> 055 * <li>no anonymous classes necessary for callback implementations; 056 * <li>the possibility to throw any application exceptions from within data access code. 057 * </ul> 058 * 059 * <p>The drawback is the dependency on interceptor configuration. However, note 060 * that this interceptor is usually <i>not</i> necessary in scenarios where the 061 * data access code always executes within transactions. A transaction will always 062 * have a thread-bound Session in the first place, so adding this interceptor to the 063 * configuration just adds value when fine-tuning Session settings like the flush mode 064 * - or when relying on exception translation. 065 * 066 * @author Juergen Hoeller 067 * @since 1.2 068 * @see org.hibernate.SessionFactory#getCurrentSession() 069 * @see HibernateTransactionManager 070 * @see HibernateTemplate 071 * @deprecated as of Spring 3.2.7, in favor of either HibernateTemplate usage or 072 * native Hibernate API usage within transactions, in combination with a general 073 * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor}. 074 * Note: This class does not have an equivalent replacement in {@code orm.hibernate4}. 075 * If you desperately need a scoped Session bound through AOP, consider the newly 076 * introduced {@link org.springframework.orm.hibernate3.support.OpenSessionInterceptor}. 077 */ 078@Deprecated 079public class HibernateInterceptor extends HibernateAccessor implements MethodInterceptor { 080 081 private boolean exceptionConversionEnabled = true; 082 083 084 /** 085 * Set whether to convert any HibernateException raised to a Spring DataAccessException, 086 * compatible with the {@code org.springframework.dao} exception hierarchy. 087 * <p>Default is "true". Turn this flag off to let the caller receive raw exceptions 088 * as-is, without any wrapping. 089 * @see org.springframework.dao.DataAccessException 090 */ 091 public void setExceptionConversionEnabled(boolean exceptionConversionEnabled) { 092 this.exceptionConversionEnabled = exceptionConversionEnabled; 093 } 094 095 096 @Override 097 public Object invoke(MethodInvocation methodInvocation) throws Throwable { 098 Session session = getSession(); 099 SessionHolder sessionHolder = 100 (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory()); 101 102 boolean existingTransaction = (sessionHolder != null && sessionHolder.containsSession(session)); 103 if (existingTransaction) { 104 logger.debug("Found thread-bound Session for HibernateInterceptor"); 105 } 106 else { 107 if (sessionHolder != null) { 108 sessionHolder.addSession(session); 109 } 110 else { 111 TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session)); 112 } 113 } 114 115 FlushMode previousFlushMode = null; 116 try { 117 previousFlushMode = applyFlushMode(session, existingTransaction); 118 enableFilters(session); 119 Object retVal = methodInvocation.proceed(); 120 flushIfNecessary(session, existingTransaction); 121 return retVal; 122 } 123 catch (HibernateException ex) { 124 if (this.exceptionConversionEnabled) { 125 throw convertHibernateAccessException(ex); 126 } 127 else { 128 throw ex; 129 } 130 } 131 finally { 132 if (existingTransaction) { 133 logger.debug("Not closing pre-bound Hibernate Session after HibernateInterceptor"); 134 disableFilters(session); 135 if (previousFlushMode != null) { 136 session.setFlushMode(previousFlushMode); 137 } 138 } 139 else { 140 SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory()); 141 if (sessionHolder == null || sessionHolder.doesNotHoldNonDefaultSession()) { 142 TransactionSynchronizationManager.unbindResource(getSessionFactory()); 143 } 144 } 145 } 146 } 147 148 /** 149 * Return a Session for use by this interceptor. 150 * @see SessionFactoryUtils#getSession 151 */ 152 protected Session getSession() { 153 return SessionFactoryUtils.getSession( 154 getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator()); 155 } 156 157}