001/*
002 * Copyright 2002-2012 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 javax.sql.DataSource;
020
021import org.apache.commons.logging.Log;
022import org.apache.commons.logging.LogFactory;
023import org.hibernate.HibernateException;
024import org.hibernate.SessionFactory;
025
026import org.springframework.beans.factory.DisposableBean;
027import org.springframework.beans.factory.FactoryBean;
028import org.springframework.beans.factory.InitializingBean;
029
030/**
031 * Abstract {@link org.springframework.beans.factory.FactoryBean} that creates
032 * a Hibernate {@link org.hibernate.SessionFactory} within a Spring application
033 * context, providing general infrastructure not related to Hibernate's
034 * specific configuration API.
035 *
036 * <p>This class implements the
037 * {@link org.springframework.dao.support.PersistenceExceptionTranslator}
038 * interface, as autodetected by Spring's
039 * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
040 * for AOP-based translation of native exceptions to Spring DataAccessExceptions.
041 * Hence, the presence of e.g. LocalSessionFactoryBean automatically enables
042 * a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions.
043 *
044 * <p>This class mainly serves as common base class for {@link LocalSessionFactoryBean}.
045 * For details on typical SessionFactory setup, see the LocalSessionFactoryBean javadoc.
046 *
047 * @author Juergen Hoeller
048 * @since 2.0
049 * @see #setExposeTransactionAwareSessionFactory
050 * @see org.hibernate.SessionFactory#getCurrentSession()
051 * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
052 * @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x
053 */
054@Deprecated
055public abstract class AbstractSessionFactoryBean extends HibernateExceptionTranslator
056                implements FactoryBean<SessionFactory>, InitializingBean, DisposableBean {
057
058        /** Logger available to subclasses */
059        protected final Log logger = LogFactory.getLog(getClass());
060
061        private DataSource dataSource;
062
063        private boolean useTransactionAwareDataSource = false;
064
065        private boolean exposeTransactionAwareSessionFactory = true;
066
067        private SessionFactory sessionFactory;
068
069
070        /**
071         * Set the DataSource to be used by the SessionFactory.
072         * If set, this will override corresponding settings in Hibernate properties.
073         * <p>If this is set, the Hibernate settings should not define
074         * a connection provider to avoid meaningless double configuration.
075         * <p>If using HibernateTransactionManager as transaction strategy, consider
076         * proxying your target DataSource with a LazyConnectionDataSourceProxy.
077         * This defers fetching of an actual JDBC Connection until the first JDBC
078         * Statement gets executed, even within JDBC transactions (as performed by
079         * HibernateTransactionManager). Such lazy fetching is particularly beneficial
080         * for read-only operations, in particular if the chances of resolving the
081         * result in the second-level cache are high.
082         * <p>As JTA and transactional JNDI DataSources already provide lazy enlistment
083         * of JDBC Connections, LazyConnectionDataSourceProxy does not add value with
084         * JTA (i.e. Spring's JtaTransactionManager) as transaction strategy.
085         * @see #setUseTransactionAwareDataSource
086         * @see HibernateTransactionManager
087         * @see org.springframework.transaction.jta.JtaTransactionManager
088         * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy
089         */
090        public void setDataSource(DataSource dataSource) {
091                this.dataSource = dataSource;
092        }
093
094        /**
095         * Return the DataSource to be used by the SessionFactory.
096         */
097        public DataSource getDataSource() {
098                return this.dataSource;
099        }
100
101        /**
102         * Set whether to use a transaction-aware DataSource for the SessionFactory,
103         * i.e. whether to automatically wrap the passed-in DataSource with Spring's
104         * TransactionAwareDataSourceProxy.
105         * <p>Default is "false": LocalSessionFactoryBean is usually used with Spring's
106         * HibernateTransactionManager or JtaTransactionManager, both of which work nicely
107         * on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are
108         * fully managed by the Hibernate/JTA transaction infrastructure in such a scenario.
109         * <p>If you switch this flag to "true", Spring's Hibernate access will be able to
110         * <i>participate in JDBC-based transactions managed outside of Hibernate</i>
111         * (for example, by Spring's DataSourceTransactionManager). This can be convenient
112         * if you need a different local transaction strategy for another O/R mapping tool,
113         * for example, but still want Hibernate access to join into those transactions.
114         * <p>A further benefit of this option is that <i>plain Sessions opened directly
115         * via the SessionFactory</i>, outside of Spring's Hibernate support, will still
116         * participate in active Spring-managed transactions. However, consider using
117         * Hibernate's {@code getCurrentSession()} method instead (see javadoc of
118         * "exposeTransactionAwareSessionFactory" property).
119         * <p><b>WARNING:</b> When using a transaction-aware JDBC DataSource in combination
120         * with OpenSessionInViewFilter/Interceptor, whether participating in JTA or
121         * external JDBC-based transactions, it is strongly recommended to set Hibernate's
122         * Connection release mode to "after_transaction" or "after_statement", which
123         * guarantees proper Connection handling in such a scenario. In contrast to that,
124         * HibernateTransactionManager generally requires release mode "on_close".
125         * <p>Note: If you want to use Hibernate's Connection release mode "after_statement"
126         * with a DataSource specified on this LocalSessionFactoryBean (for example, a
127         * JTA-aware DataSource fetched from JNDI), switch this setting to "true".
128         * Otherwise, the ConnectionProvider used underneath will vote against aggressive
129         * release and thus silently switch to release mode "after_transaction".
130         * @see #setDataSource
131         * @see #setExposeTransactionAwareSessionFactory
132         * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
133         * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
134         * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
135         * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
136         * @see HibernateTransactionManager
137         * @see org.springframework.transaction.jta.JtaTransactionManager
138         */
139        public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
140                this.useTransactionAwareDataSource = useTransactionAwareDataSource;
141        }
142
143        /**
144         * Return whether to use a transaction-aware DataSource for the SessionFactory.
145         */
146        protected boolean isUseTransactionAwareDataSource() {
147                return this.useTransactionAwareDataSource;
148        }
149
150        /**
151         * Set whether to expose a transaction-aware current Session from the
152         * SessionFactory's {@code getCurrentSession()} method, returning the
153         * Session that's associated with the current Spring-managed transaction, if any.
154         * <p>Default is "true", letting data access code work with the plain
155         * Hibernate SessionFactory and its {@code getCurrentSession()} method,
156         * while still being able to participate in current Spring-managed transactions:
157         * with any transaction management strategy, either local or JTA / EJB CMT,
158         * and any transaction synchronization mechanism, either Spring or JTA.
159         * Furthermore, {@code getCurrentSession()} will also seamlessly work with
160         * a request-scoped Session managed by OpenSessionInViewFilter/Interceptor.
161         * <p>Turn this flag off to expose the plain Hibernate SessionFactory with
162         * Hibernate's default {@code getCurrentSession()} behavior, supporting
163         * plain JTA synchronization only. Alternatively, simply override the
164         * corresponding Hibernate property "hibernate.current_session_context_class".
165         * @see SpringSessionContext
166         * @see org.hibernate.SessionFactory#getCurrentSession()
167         * @see org.springframework.transaction.jta.JtaTransactionManager
168         * @see HibernateTransactionManager
169         * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
170         * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
171         */
172        public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) {
173                this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory;
174        }
175
176        /**
177         * Return whether to expose a transaction-aware proxy for the SessionFactory.
178         */
179        protected boolean isExposeTransactionAwareSessionFactory() {
180                return this.exposeTransactionAwareSessionFactory;
181        }
182
183
184        /**
185         * Build and expose the SessionFactory.
186         * @see #buildSessionFactory()
187         * @see #wrapSessionFactoryIfNecessary
188         */
189        @Override
190        public void afterPropertiesSet() throws Exception {
191                SessionFactory rawSf = buildSessionFactory();
192                this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);
193                afterSessionFactoryCreation();
194        }
195
196        /**
197         * Wrap the given SessionFactory with a proxy, if demanded.
198         * <p>The default implementation simply returns the given SessionFactory as-is.
199         * Subclasses may override this to implement transaction awareness through
200         * a SessionFactory proxy, for example.
201         * @param rawSf the raw SessionFactory as built by {@link #buildSessionFactory()}
202         * @return the SessionFactory reference to expose
203         * @see #buildSessionFactory()
204         */
205        protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) {
206                return rawSf;
207        }
208
209        /**
210         * Return the exposed SessionFactory.
211         * Will throw an exception if not initialized yet.
212         * @return the SessionFactory (never {@code null})
213         * @throws IllegalStateException if the SessionFactory has not been initialized yet
214         */
215        protected final SessionFactory getSessionFactory() {
216                if (this.sessionFactory == null) {
217                        throw new IllegalStateException("SessionFactory not initialized yet");
218                }
219                return this.sessionFactory;
220        }
221
222        /**
223         * Close the SessionFactory on bean factory shutdown.
224         */
225        @Override
226        public void destroy() throws HibernateException {
227                logger.info("Closing Hibernate SessionFactory");
228                try {
229                        beforeSessionFactoryDestruction();
230                }
231                finally {
232                        this.sessionFactory.close();
233                }
234        }
235
236
237        /**
238         * Return the singleton SessionFactory.
239         */
240        @Override
241        public SessionFactory getObject() {
242                return this.sessionFactory;
243        }
244
245        @Override
246        public Class<? extends SessionFactory> getObjectType() {
247                return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class);
248        }
249
250        @Override
251        public boolean isSingleton() {
252                return true;
253        }
254
255
256        /**
257         * Build the underlying Hibernate SessionFactory.
258         * @return the raw SessionFactory (potentially to be wrapped with a
259         * transaction-aware proxy before it is exposed to the application)
260         * @throws Exception in case of initialization failure
261         */
262        protected abstract SessionFactory buildSessionFactory() throws Exception;
263
264        /**
265         * Hook that allows post-processing after the SessionFactory has been
266         * successfully created. The SessionFactory is already available through
267         * {@code getSessionFactory()} at this point.
268         * <p>This implementation is empty.
269         * @throws Exception in case of initialization failure
270         * @see #getSessionFactory()
271         */
272        protected void afterSessionFactoryCreation() throws Exception {
273        }
274
275        /**
276         * Hook that allows shutdown processing before the SessionFactory
277         * will be closed. The SessionFactory is still available through
278         * {@code getSessionFactory()} at this point.
279         * <p>This implementation is empty.
280         * @see #getSessionFactory()
281         */
282        protected void beforeSessionFactoryDestruction() {
283        }
284
285}