Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » orm » hibernate3 » [javadoc | source]
    1   /*
    2    * Copyright 2002-2008 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 javax.sql.DataSource;
   20   
   21   import org.apache.commons.logging.Log;
   22   import org.apache.commons.logging.LogFactory;
   23   import org.hibernate.HibernateException;
   24   import org.hibernate.JDBCException;
   25   import org.hibernate.SessionFactory;
   26   
   27   import org.springframework.beans.factory.DisposableBean;
   28   import org.springframework.beans.factory.FactoryBean;
   29   import org.springframework.beans.factory.InitializingBean;
   30   import org.springframework.dao.DataAccessException;
   31   import org.springframework.dao.support.PersistenceExceptionTranslator;
   32   import org.springframework.jdbc.support.SQLExceptionTranslator;
   33   
   34   /**
   35    * Abstract {@link org.springframework.beans.factory.FactoryBean} that creates
   36    * a Hibernate {@link org.hibernate.SessionFactory} within a Spring application
   37    * context, providing general infrastructure not related to Hibernate's
   38    * specific configuration API.
   39    *
   40    * <p>This class implements the
   41    * {@link org.springframework.dao.support.PersistenceExceptionTranslator}
   42    * interface, as autodetected by Spring's
   43    * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
   44    * for AOP-based translation of native exceptions to Spring DataAccessExceptions.
   45    * Hence, the presence of e.g. LocalSessionFactoryBean automatically enables
   46    * a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions.
   47    *
   48    * <p>This class mainly serves as common base class for {@link LocalSessionFactoryBean}.
   49    * For details on typical SessionFactory setup, see the LocalSessionFactoryBean javadoc.
   50    *
   51    * @author Juergen Hoeller
   52    * @since 2.0
   53    * @see #setExposeTransactionAwareSessionFactory
   54    * @see org.hibernate.SessionFactory#getCurrentSession()
   55    * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
   56    */
   57   public abstract class AbstractSessionFactoryBean
   58   		implements FactoryBean, InitializingBean, DisposableBean, PersistenceExceptionTranslator {
   59   
   60   	/** Logger available to subclasses */
   61   	protected final Log logger = LogFactory.getLog(getClass());
   62   
   63   	private DataSource dataSource;
   64   
   65   	private boolean useTransactionAwareDataSource = false;
   66   
   67   	private boolean exposeTransactionAwareSessionFactory = true;
   68   
   69   	private SQLExceptionTranslator jdbcExceptionTranslator;
   70   
   71   	private SessionFactory sessionFactory;
   72   
   73   
   74   	/**
   75   	 * Set the DataSource to be used by the SessionFactory.
   76   	 * If set, this will override corresponding settings in Hibernate properties.
   77   	 * <p>If this is set, the Hibernate settings should not define
   78   	 * a connection provider to avoid meaningless double configuration.
   79   	 * <p>If using HibernateTransactionManager as transaction strategy, consider
   80   	 * proxying your target DataSource with a LazyConnectionDataSourceProxy.
   81   	 * This defers fetching of an actual JDBC Connection until the first JDBC
   82   	 * Statement gets executed, even within JDBC transactions (as performed by
   83   	 * HibernateTransactionManager). Such lazy fetching is particularly beneficial
   84   	 * for read-only operations, in particular if the chances of resolving the
   85   	 * result in the second-level cache are high.
   86   	 * <p>As JTA and transactional JNDI DataSources already provide lazy enlistment
   87   	 * of JDBC Connections, LazyConnectionDataSourceProxy does not add value with
   88   	 * JTA (i.e. Spring's JtaTransactionManager) as transaction strategy.
   89   	 * @see #setUseTransactionAwareDataSource
   90   	 * @see HibernateTransactionManager
   91   	 * @see org.springframework.transaction.jta.JtaTransactionManager
   92   	 * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy
   93   	 */
   94   	public void setDataSource(DataSource dataSource) {
   95   		this.dataSource = dataSource;
   96   	}
   97   
   98   	/**
   99   	 * Return the DataSource to be used by the SessionFactory.
  100   	 */
  101   	public DataSource getDataSource() {
  102   		return this.dataSource;
  103   	}
  104   
  105   	/**
  106   	 * Set whether to use a transaction-aware DataSource for the SessionFactory,
  107   	 * i.e. whether to automatically wrap the passed-in DataSource with Spring's
  108   	 * TransactionAwareDataSourceProxy.
  109   	 * <p>Default is "false": LocalSessionFactoryBean is usually used with Spring's
  110   	 * HibernateTransactionManager or JtaTransactionManager, both of which work nicely
  111   	 * on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are
  112   	 * fully managed by the Hibernate/JTA transaction infrastructure in such a scenario.
  113   	 * <p>If you switch this flag to "true", Spring's Hibernate access will be able to
  114   	 * <i>participate in JDBC-based transactions managed outside of Hibernate</i>
  115   	 * (for example, by Spring's DataSourceTransactionManager). This can be convenient
  116   	 * if you need a different local transaction strategy for another O/R mapping tool,
  117   	 * for example, but still want Hibernate access to join into those transactions.
  118   	 * <p>A further benefit of this option is that <i>plain Sessions opened directly
  119   	 * via the SessionFactory</i>, outside of Spring's Hibernate support, will still
  120   	 * participate in active Spring-managed transactions. However, consider using
  121   	 * Hibernate's <code>getCurrentSession()</code> method instead (see javadoc of
  122   	 * "exposeTransactionAwareSessionFactory" property).
  123   	 * <p><b>WARNING:</b> When using a transaction-aware JDBC DataSource in combination
  124   	 * with OpenSessionInViewFilter/Interceptor, whether participating in JTA or
  125   	 * external JDBC-based transactions, it is strongly recommended to set Hibernate's
  126   	 * Connection release mode to "after_transaction" or "after_statement", which
  127   	 * guarantees proper Connection handling in such a scenario. In contrast to that,
  128   	 * HibernateTransactionManager generally requires release mode "on_close".
  129   	 * <p>Note: If you want to use Hibernate's Connection release mode "after_statement"
  130   	 * with a DataSource specified on this LocalSessionFactoryBean (for example, a
  131   	 * JTA-aware DataSource fetched from JNDI), switch this setting to "true".
  132   	 * Otherwise, the ConnectionProvider used underneath will vote against aggressive
  133   	 * release and thus silently switch to release mode "after_transaction".
  134   	 * @see #setDataSource
  135   	 * @see #setExposeTransactionAwareSessionFactory
  136   	 * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
  137   	 * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
  138   	 * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
  139   	 * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
  140   	 * @see HibernateTransactionManager
  141   	 * @see org.springframework.transaction.jta.JtaTransactionManager
  142   	 */
  143   	public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
  144   		this.useTransactionAwareDataSource = useTransactionAwareDataSource;
  145   	}
  146   
  147   	/**
  148   	 * Return whether to use a transaction-aware DataSource for the SessionFactory.
  149   	 */
  150   	protected boolean isUseTransactionAwareDataSource() {
  151   		return this.useTransactionAwareDataSource;
  152   	}
  153   
  154   	/**
  155   	 * Set whether to expose a transaction-aware current Session from the
  156   	 * SessionFactory's <code>getCurrentSession()</code> method, returning the
  157   	 * Session that's associated with the current Spring-managed transaction, if any.
  158   	 * <p>Default is "true", letting data access code work with the plain
  159   	 * Hibernate SessionFactory and its <code>getCurrentSession()</code> method,
  160   	 * while still being able to participate in current Spring-managed transactions:
  161   	 * with any transaction management strategy, either local or JTA / EJB CMT,
  162   	 * and any transaction synchronization mechanism, either Spring or JTA.
  163   	 * Furthermore, <code>getCurrentSession()</code> will also seamlessly work with
  164   	 * a request-scoped Session managed by OpenSessionInViewFilter/Interceptor.
  165   	 * <p>Turn this flag off to expose the plain Hibernate SessionFactory with
  166   	 * Hibernate's default <code>getCurrentSession()</code> behavior, supporting
  167   	 * plain JTA synchronization only. Alternatively, simply override the
  168   	 * corresponding Hibernate property "hibernate.current_session_context_class".
  169   	 * @see SpringSessionContext
  170   	 * @see org.hibernate.SessionFactory#getCurrentSession()
  171   	 * @see org.springframework.transaction.jta.JtaTransactionManager
  172   	 * @see HibernateTransactionManager
  173   	 * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
  174   	 * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
  175   	 */
  176   	public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) {
  177   		this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory;
  178   	}
  179   
  180   	/**
  181   	 * Return whether to expose a transaction-aware proxy for the SessionFactory.
  182   	 */
  183   	protected boolean isExposeTransactionAwareSessionFactory() {
  184   		return this.exposeTransactionAwareSessionFactory;
  185   	}
  186   
  187   	/**
  188   	 * Set the JDBC exception translator for the SessionFactory,
  189   	 * exposed via the PersistenceExceptionTranslator interface.
  190   	 * <p>Applied to any SQLException root cause of a Hibernate JDBCException,
  191   	 * overriding Hibernate's default SQLException translation (which is
  192   	 * based on Hibernate's Dialect for a specific target database).
  193   	 * @param jdbcExceptionTranslator the exception translator
  194   	 * @see java.sql.SQLException
  195   	 * @see org.hibernate.JDBCException
  196   	 * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
  197   	 * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
  198   	 * @see org.springframework.dao.support.PersistenceExceptionTranslator
  199   	 */
  200   	public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
  201   		this.jdbcExceptionTranslator = jdbcExceptionTranslator;
  202   	}
  203   
  204   
  205   	/**
  206   	 * Build and expose the SessionFactory.
  207   	 * @see #buildSessionFactory()
  208   	 * @see #wrapSessionFactoryIfNecessary
  209   	 */
  210   	public void afterPropertiesSet() throws Exception {
  211   		SessionFactory rawSf = buildSessionFactory();
  212   		this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);
  213   		afterSessionFactoryCreation();
  214   	}
  215   
  216   	/**
  217   	 * Wrap the given SessionFactory with a proxy, if demanded.
  218   	 * <p>The default implementation simply returns the given SessionFactory as-is.
  219   	 * Subclasses may override this to implement transaction awareness through
  220   	 * a SessionFactory proxy, for example.
  221   	 * @param rawSf the raw SessionFactory as built by {@link #buildSessionFactory()}
  222   	 * @return the SessionFactory reference to expose
  223   	 * @see #buildSessionFactory()
  224   	 */
  225   	protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) {
  226   		return rawSf;
  227   	}
  228   
  229   	/**
  230   	 * Return the exposed SessionFactory.
  231   	 * Will throw an exception if not initialized yet.
  232   	 * @return the SessionFactory (never <code>null</code>)
  233   	 * @throws IllegalStateException if the SessionFactory has not been initialized yet
  234   	 */
  235   	protected final SessionFactory getSessionFactory() {
  236   		if (this.sessionFactory == null) {
  237   			throw new IllegalStateException("SessionFactory not initialized yet");
  238   		}
  239   		return this.sessionFactory;
  240   	}
  241   
  242   	/**
  243   	 * Close the SessionFactory on bean factory shutdown.
  244   	 */
  245   	public void destroy() throws HibernateException {
  246   		logger.info("Closing Hibernate SessionFactory");
  247   		try {
  248   			beforeSessionFactoryDestruction();
  249   		}
  250   		finally {
  251   			this.sessionFactory.close();
  252   		}
  253   	}
  254   
  255   
  256   	/**
  257   	 * Return the singleton SessionFactory.
  258   	 */
  259   	public Object getObject() {
  260   		return this.sessionFactory;
  261   	}
  262   
  263   	public Class getObjectType() {
  264   		return (this.sessionFactory != null) ? this.sessionFactory.getClass() : SessionFactory.class;
  265   	}
  266   
  267   	public boolean isSingleton() {
  268   		return true;
  269   	}
  270   
  271   
  272   	/**
  273   	 * Implementation of the PersistenceExceptionTranslator interface,
  274   	 * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor.
  275   	 * <p>Converts the exception if it is a HibernateException;
  276   	 * else returns <code>null</code> to indicate an unknown exception.
  277   	 * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
  278   	 * @see #convertHibernateAccessException
  279   	 */
  280   	public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
  281   		if (ex instanceof HibernateException) {
  282   			return convertHibernateAccessException((HibernateException) ex);
  283   		}
  284   		return null;
  285   	}
  286   
  287   	/**
  288   	 * Convert the given HibernateException to an appropriate exception from the
  289   	 * <code>org.springframework.dao</code> hierarchy.
  290   	 * <p>Will automatically apply a specified SQLExceptionTranslator to a
  291   	 * Hibernate JDBCException, else rely on Hibernate's default translation.
  292   	 * @param ex HibernateException that occured
  293   	 * @return a corresponding DataAccessException
  294   	 * @see SessionFactoryUtils#convertHibernateAccessException
  295   	 * @see #setJdbcExceptionTranslator
  296   	 */
  297   	protected DataAccessException convertHibernateAccessException(HibernateException ex) {
  298   		if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) {
  299   			JDBCException jdbcEx = (JDBCException) ex;
  300   			return this.jdbcExceptionTranslator.translate(
  301   					"Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
  302   		}
  303   		return SessionFactoryUtils.convertHibernateAccessException(ex);
  304   	}
  305   
  306   
  307   	/**
  308   	 * Build the underlying Hibernate SessionFactory.
  309   	 * @return the raw SessionFactory (potentially to be wrapped with a
  310   	 * transaction-aware proxy before it is exposed to the application)
  311   	 * @throws Exception in case of initialization failure
  312   	 */
  313   	protected abstract SessionFactory buildSessionFactory() throws Exception;
  314   
  315   	/**
  316   	 * Hook that allows post-processing after the SessionFactory has been
  317   	 * successfully created. The SessionFactory is already available through
  318   	 * <code>getSessionFactory()</code> at this point.
  319   	 * <p>This implementation is empty.
  320   	 * @throws Exception in case of initialization failure
  321   	 * @see #getSessionFactory()
  322   	 */
  323   	protected void afterSessionFactoryCreation() throws Exception {
  324   	}
  325   
  326   	/**
  327   	 * Hook that allows shutdown processing before the SessionFactory
  328   	 * will be closed. The SessionFactory is still available through
  329   	 * <code>getSessionFactory()</code> at this point.
  330   	 * <p>This implementation is empty.
  331   	 * @see #getSessionFactory()
  332   	 */
  333   	protected void beforeSessionFactoryDestruction() {
  334   	}
  335   
  336   }

Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » orm » hibernate3 » [javadoc | source]