KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > orm > hibernate3 > AbstractSessionFactoryBean


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.orm.hibernate3;
18
19 import java.lang.reflect.InvocationHandler JavaDoc;
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.lang.reflect.Proxy JavaDoc;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.hibernate.HibernateException;
27 import org.hibernate.JDBCException;
28 import org.hibernate.SessionFactory;
29 import org.hibernate.engine.SessionFactoryImplementor;
30
31 import org.springframework.beans.factory.DisposableBean;
32 import org.springframework.beans.factory.FactoryBean;
33 import org.springframework.beans.factory.InitializingBean;
34 import org.springframework.dao.DataAccessException;
35 import org.springframework.dao.support.PersistenceExceptionTranslator;
36 import org.springframework.jdbc.support.SQLExceptionTranslator;
37
38 /**
39  * Abstract {@link org.springframework.beans.factory.FactoryBean} that creates
40  * a Hibernate {@link org.hibernate.SessionFactory} within a Spring application
41  * context. Supports building a transaction-aware SessionFactory proxy that
42  * exposes a Spring-managed transactional Session as "current Session".
43  *
44  * <p>This class also implements the
45  * {@link org.springframework.dao.support.PersistenceExceptionTranslator}
46  * interface, as autodetected by Spring's
47  * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
48  * for AOP-based translation of native exceptions to Spring DataAccessExceptions.
49  * Hence, the presence of e.g. LocalSessionFactoryBean automatically enables
50  * a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions.
51  *
52  * <p>This class mainly serves as common base class for {@link LocalSessionFactoryBean}.
53  * For details on typical SessionFactory setup, see the LocalSessionFactoryBean javadoc.
54  *
55  * @author Juergen Hoeller
56  * @since 2.0
57  * @see #setExposeTransactionAwareSessionFactory
58  * @see org.hibernate.SessionFactory#getCurrentSession()
59  * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
60  */

61 public abstract class AbstractSessionFactoryBean
62         implements FactoryBean, InitializingBean, DisposableBean, PersistenceExceptionTranslator {
63
64     /** Logger available to subclasses */
65     protected final Log logger = LogFactory.getLog(getClass());
66
67     private boolean exposeTransactionAwareSessionFactory = true;
68
69     private SQLExceptionTranslator jdbcExceptionTranslator;
70
71     private SessionFactory sessionFactory;
72
73
74     /**
75      * Set whether to expose a transaction-aware proxy for the SessionFactory,
76      * returning the Session that's associated with the current Spring-managed
77      * transaction on <code>getCurrentSession()</code>, if any.
78      * <p>Default is "true", letting data access code work with the plain
79      * Hibernate SessionFactory and its <code>getCurrentSession()</code> method,
80      * while still being able to participate in current Spring-managed transactions:
81      * with any transaction management strategy, either local or JTA / EJB CMT,
82      * and any transaction synchronization mechanism, either Spring or JTA.
83      * Furthermore, <code>getCurrentSession()</code> will also seamlessly work with
84      * a request-scoped Session managed by OpenSessionInViewFilter/Interceptor.
85      * <p>Turn this flag off to expose the plain Hibernate SessionFactory with
86      * Hibernate's default <code>getCurrentSession()</code> behavior, where
87      * Hibernate 3.0.x only supports plain JTA synchronization. On Hibernate 3.1+,
88      * such a plain SessionFactory will by default have a SpringSessionContext
89      * registered to nevertheless provide Spring-managed Sessions; this can be
90      * overridden through the corresponding Hibernate property
91      * "hibernate.current_session_context_class".
92      * @see org.hibernate.SessionFactory#getCurrentSession()
93      * @see org.springframework.transaction.jta.JtaTransactionManager
94      * @see HibernateTransactionManager
95      * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
96      * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
97      * @see SpringSessionContext
98      */

99     public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) {
100         this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory;
101     }
102
103     /**
104      * Return whether to expose a transaction-aware proxy for the SessionFactory.
105      */

106     protected boolean isExposeTransactionAwareSessionFactory() {
107         return exposeTransactionAwareSessionFactory;
108     }
109
110     /**
111      * Set the JDBC exception translator for the SessionFactory,
112      * exposed via the PersistenceExceptionTranslator interface.
113      * <p>Applied to any SQLException root cause of a Hibernate JDBCException,
114      * overriding Hibernate's default SQLException translation (which is
115      * based on Hibernate's Dialect for a specific target database).
116      * @param jdbcExceptionTranslator the exception translator
117      * @see java.sql.SQLException
118      * @see org.hibernate.JDBCException
119      * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
120      * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
121      * @see org.springframework.dao.support.PersistenceExceptionTranslator
122      */

123     public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
124         this.jdbcExceptionTranslator = jdbcExceptionTranslator;
125     }
126
127
128     /**
129      * Build and expose the SessionFactory.
130      * @see #buildSessionFactory()
131      * @see #wrapSessionFactoryIfNecessary
132      */

133     public void afterPropertiesSet() throws Exception JavaDoc {
134         SessionFactory rawSf = buildSessionFactory();
135         this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);
136         afterSessionFactoryCreation();
137     }
138
139     /**
140      * Wrap the given SessionFactory with a transaction-aware proxy, if demanded.
141      * @param rawSf the raw SessionFactory as built by <code>buildSessionFactory()</code>
142      * @return the SessionFactory reference to expose
143      * @see #buildSessionFactory()
144      * @see #getTransactionAwareSessionFactoryProxy
145      */

146     protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) {
147         if (isExposeTransactionAwareSessionFactory()) {
148              return getTransactionAwareSessionFactoryProxy(rawSf);
149         }
150         else {
151             return rawSf;
152         }
153     }
154
155     /**
156      * Wrap the given SessionFactory with a proxy that delegates every method call
157      * to it but delegates <code>getCurrentSession</code> calls to SessionFactoryUtils,
158      * for participating in Spring-managed transactions.
159      * @param target the original SessionFactory to wrap
160      * @return the wrapped SessionFactory
161      * @see org.hibernate.SessionFactory#getCurrentSession()
162      * @see SessionFactoryUtils#doGetSession(org.hibernate.SessionFactory, boolean)
163      */

164     protected SessionFactory getTransactionAwareSessionFactoryProxy(SessionFactory target) {
165         Class JavaDoc sfInterface = SessionFactory.class;
166         if (target instanceof SessionFactoryImplementor) {
167             sfInterface = SessionFactoryImplementor.class;
168         }
169         return (SessionFactory) Proxy.newProxyInstance(sfInterface.getClassLoader(),
170                 new Class JavaDoc[] {sfInterface}, new TransactionAwareInvocationHandler(target));
171     }
172
173     /**
174      * Return the exposed SessionFactory.
175      * @throws IllegalStateException if the SessionFactory has not been initialized yet
176      */

177     protected final SessionFactory getSessionFactory() {
178         if (this.sessionFactory == null) {
179             throw new IllegalStateException JavaDoc("SessionFactory not initialized yet");
180         }
181         return this.sessionFactory;
182     }
183
184     /**
185      * Close the SessionFactory on bean factory shutdown.
186      */

187     public void destroy() throws HibernateException {
188         logger.info("Closing Hibernate SessionFactory");
189         try {
190             beforeSessionFactoryDestruction();
191         }
192         finally {
193             this.sessionFactory.close();
194         }
195     }
196
197
198     /**
199      * Return the singleton SessionFactory.
200      */

201     public Object JavaDoc getObject() {
202         return this.sessionFactory;
203     }
204
205     public Class JavaDoc getObjectType() {
206         return (this.sessionFactory != null) ? this.sessionFactory.getClass() : SessionFactory.class;
207     }
208
209     public boolean isSingleton() {
210         return true;
211     }
212
213
214     /**
215      * Implementation of the PersistenceExceptionTranslator interface,
216      * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor.
217      * <p>Converts the exception if it is a HibernateException;
218      * else returns <code>null</code> to indicate an unknown exception.
219      * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
220      * @see #convertHibernateAccessException
221      */

222     public DataAccessException translateExceptionIfPossible(RuntimeException JavaDoc ex) {
223         if (ex instanceof HibernateException) {
224             return convertHibernateAccessException((HibernateException) ex);
225         }
226         return null;
227     }
228
229     /**
230      * Convert the given HibernateException to an appropriate exception from the
231      * <code>org.springframework.dao</code> hierarchy.
232      * <p>Will automatically apply a specified SQLExceptionTranslator to a
233      * Hibernate JDBCException, else rely on Hibernate's default translation.
234      * @param ex HibernateException that occured
235      * @return a corresponding DataAccessException
236      * @see SessionFactoryUtils#convertHibernateAccessException
237      * @see #setJdbcExceptionTranslator
238      */

239     protected DataAccessException convertHibernateAccessException(HibernateException ex) {
240         if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
241             JDBCException jdbcEx = (JDBCException) ex;
242             return this.jdbcExceptionTranslator.translate(
243                     "Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
244         }
245         return SessionFactoryUtils.convertHibernateAccessException(ex);
246     }
247
248
249     /**
250      * Build the underlying Hibernate SessionFactory.
251      * @return the raw SessionFactory (potentially to be wrapped with a
252      * transaction-aware proxy before it is exposed to the application)
253      * @throws Exception in case of initialization failure
254      */

255     protected abstract SessionFactory buildSessionFactory() throws Exception JavaDoc;
256
257     /**
258      * Hook that allows post-processing after the SessionFactory has been
259      * successfully created. The SessionFactory is already available through
260      * <code>getSessionFactory()</code> at this point.
261      * <p>This implementation is empty.
262      * @see #getSessionFactory()
263      */

264     protected void afterSessionFactoryCreation() throws Exception JavaDoc {
265     }
266
267     /**
268      * Hook that allows shutdown processing before the SessionFactory
269      * will be closed. The SessionFactory is still available through
270      * <code>getSessionFactory()</code> at this point.
271      * <p>This implementation is empty.
272      * @see #getSessionFactory()
273      */

274     protected void beforeSessionFactoryDestruction() {
275     }
276
277
278     /**
279      * Invocation handler that delegates <code>getCurrentSession()</code> calls
280      * to SessionFactoryUtils, for being aware of thread-bound transactions.
281      */

282     private static class TransactionAwareInvocationHandler implements InvocationHandler JavaDoc {
283
284         private final SessionFactory target;
285
286         public TransactionAwareInvocationHandler(SessionFactory target) {
287             this.target = target;
288         }
289
290         public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
291             // Invocation on SessionFactory/SessionFactoryImplementor interface coming in...
292

293             if (method.getName().equals("getCurrentSession")) {
294                 // Handle getCurrentSession method: return transactional Session, if any.
295
try {
296                     return SessionFactoryUtils.doGetSession((SessionFactory) proxy, false);
297                 }
298                 catch (IllegalStateException JavaDoc ex) {
299                     throw new HibernateException(ex.getMessage());
300                 }
301             }
302             else if (method.getName().equals("equals")) {
303                 // Only consider equal when proxies are identical.
304
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
305             }
306             else if (method.getName().equals("hashCode")) {
307                 // Use hashCode of SessionFactory proxy.
308
return new Integer JavaDoc(hashCode());
309             }
310
311             // Invoke method on target SessionFactory.
312
try {
313                 return method.invoke(this.target, args);
314             }
315             catch (InvocationTargetException JavaDoc ex) {
316                 throw ex.getTargetException();
317             }
318         }
319     }
320
321 }
322
Popular Tags