diff --git a/org.springframework.integration-tests/.classpath b/org.springframework.integration-tests/.classpath index 26074edfbc7..d1ea9d34812 100644 --- a/org.springframework.integration-tests/.classpath +++ b/org.springframework.integration-tests/.classpath @@ -21,6 +21,7 @@ + @@ -69,6 +70,7 @@ + diff --git a/org.springframework.integration-tests/.springBeans b/org.springframework.integration-tests/.springBeans index 55e47c55ec7..5e600dfe9f4 100644 --- a/org.springframework.integration-tests/.springBeans +++ b/org.springframework.integration-tests/.springBeans @@ -1,12 +1,13 @@ 1 - + + src/test/resources/org/springframework/orm/hibernate3/LocalSessionFactoryBeanXmlConfig-context.xml diff --git a/org.springframework.integration-tests/integration-tests.iml b/org.springframework.integration-tests/integration-tests.iml index 13421323256..ea3643ecf3d 100644 --- a/org.springframework.integration-tests/integration-tests.iml +++ b/org.springframework.integration-tests/integration-tests.iml @@ -31,6 +31,7 @@ + @@ -446,6 +447,17 @@ + + + + + + + + + + + diff --git a/org.springframework.integration-tests/ivy.xml b/org.springframework.integration-tests/ivy.xml index 455fd86e83b..6b9e9730375 100644 --- a/org.springframework.integration-tests/ivy.xml +++ b/org.springframework.integration-tests/ivy.xml @@ -74,7 +74,9 @@ + + diff --git a/org.springframework.integration-tests/src/test/java/org/springframework/orm/hibernate3/HibernateSessionFactoryConfigurationTests.java b/org.springframework.integration-tests/src/test/java/org/springframework/orm/hibernate3/HibernateSessionFactoryConfigurationTests.java new file mode 100644 index 00000000000..8d72df5d4f4 --- /dev/null +++ b/org.springframework.integration-tests/src/test/java/org/springframework/orm/hibernate3/HibernateSessionFactoryConfigurationTests.java @@ -0,0 +1,352 @@ +/* + * Copyright 2002-2011 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 static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +import java.io.File; +import java.util.List; + +import javax.inject.Inject; +import javax.sql.DataSource; + +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.cfg.AnnotationConfiguration; +import org.hibernate.classic.Session; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Feature; +import org.springframework.context.annotation.FeatureConfiguration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.ImportResource; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; +import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; +import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBuilder; +import org.springframework.orm.hibernate3.scannable.Foo; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.config.TxAnnotationDriven; + +/** + * Integration tests for configuring Hibernate SessionFactory types + * without using a FactoryBean, e.g., within a {@link Configuration} class. + * + * @author Chris Beams + * @since 3.1 + */ +public class HibernateSessionFactoryConfigurationTests { + + @Test + public void usingLocalSessionFactoryBean() { + saveAndRetriveEntity(LocalSessionFactoryBeanXmlConfig.class); + } + + @Test + public void usingAnnotationSessionFactoryBean() { + saveAndRetriveEntity(AnnotationSessionFactoryBeanXmlConfig.class); + } + + @Ignore @Test + public void usingNativeHibernateConfiguration() { + saveAndRetriveEntity(NativeHibernateConfig.class); + } + + @Test + public void usingSessionFactoryBuilder_withConfigurationCallback() { + saveAndRetriveEntity(SessionFactoryConfig_withConfigurationCallback.class); + } + + @Test + public void usingAnnotationSessionFactoryBuilder() { + saveAndRetriveEntity(AnnotationSessionFactoryConfig.class); + } + + @Test + public void usingAnnotationSessionFactoryBuilder_withConfigurationCallback() { + saveAndRetriveEntity(AnnotationSessionFactoryConfig_withConfigurationCallback.class); + } + + @Test + public void usingAnnotationSessionFactoryBuilder_withPackagesToScan() { + saveAndRetriveEntity(AnnotationSessionFactoryConfig_withPackagesToScan.class); + } + + @Test + public void usingAnnotationSessionFactoryBuilder_withAnnotatedClasses() { + saveAndRetriveEntity(AnnotationSessionFactoryConfig_withAnnotatedClasses.class); + } + + + @Test(expected=DataAccessException.class) + public void exceptionTranslation_withLocalSessionFactoryBean() { + causeException(LocalSessionFactoryBeanXmlConfig.class, RepositoryConfig.class); + } + + @Test(expected=DataAccessException.class) + public void exceptionTranslation_withSessionFactoryBuilder() { + causeException(SessionFactoryConfig_withConfigurationCallback.class, + RepositoryConfig.class); + } + + @Test + public void usingSessionFactoryBuilder_withCustomConfigurationClass() { + saveAndRetriveEntity(SessionFactoryConfig_withCustomConfigurationClass.class); + } + + @Test(expected=IllegalStateException.class) + public void usingSessionFactoryBuilder_withLateCustomConfigurationClass() throws Throwable { + try { + saveAndRetriveEntity(SessionFactoryConfig_withLateCustomConfigurationClass.class); + } catch (BeanCreationException ex) { + Throwable cause = ex.getRootCause(); + assertThat(cause.getMessage().startsWith("setConfigurationClass() must be called before"), is(true)); + throw cause; + } + } + + + private void saveAndRetriveEntity(Class configClass) { + SessionFactory sessionFactory = new AnnotationConfigApplicationContext(configClass).getBean(SessionFactory.class); + Session session = sessionFactory.openSession(); + Transaction tx = session.beginTransaction(); + Foo foo = new Foo(); + foo.setName("f1"); + session.save(foo); + + Foo f1 = (Foo) session.createQuery("from Foo where name = 'f1'").uniqueResult(); + assertThat("No foo with name='f1' found!", f1, notNullValue()); + assertThat(f1.getName(), is("f1")); + + tx.rollback(); + } + + private void causeException(Class... configClasses) { + FooRepository fooRepository = new AnnotationConfigApplicationContext(configClasses).getBean(FooRepository.class); + fooRepository.findAll(); // will throw + } + + + @Configuration + static class DataConfig { + @Bean + DataSource dataSource() { + return new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.HSQL) + .build(); + } + } + + + @Configuration + @ImportResource("org/springframework/orm/hibernate3/LocalSessionFactoryBeanXmlConfig-context.xml") + static class LocalSessionFactoryBeanXmlConfig extends DataConfig { + } + + + interface FooRepository { + List findAll(); + } + + @Repository + public static class HibernateFooRepository implements FooRepository { + private final SessionFactory sessionFactory; + public HibernateFooRepository(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + @Transactional + @SuppressWarnings("unchecked") + public List findAll() { + return sessionFactory.getCurrentSession().createQuery("from Bogus").list(); + } + } + + + @Configuration + @Import(TxConfig.class) + static class RepositoryConfig { + @Inject SessionFactory sessionFactory; + + @Bean + FooRepository fooRepository() { + return new HibernateFooRepository(sessionFactory); + } + + @Bean + PlatformTransactionManager txManager() { + return new HibernateTransactionManager(sessionFactory); + } + + @Bean + PersistenceExceptionTranslationPostProcessor exceptionTranslationPostProcessor() { + return new PersistenceExceptionTranslationPostProcessor(); + } + + @Bean + PersistenceExceptionTranslator exceptionTranslator() { + return new HibernateExceptionTranslator(); + } + } + + + @FeatureConfiguration + static class TxConfig { + @Feature + TxAnnotationDriven tx(PlatformTransactionManager txManager) { + return new TxAnnotationDriven(txManager); + } + } + + + @Configuration + @ImportResource("org/springframework/orm/hibernate3/AnnotationSessionFactoryBeanXmlConfig-context.xml") + static class AnnotationSessionFactoryBeanXmlConfig extends DataConfig { + } + + + @Configuration + static class NativeHibernateConfig { + @Bean + SessionFactory sessionFactory() { + org.hibernate.cfg.Configuration cfg = new AnnotationConfiguration(); + return cfg.buildSessionFactory(); + } + } + + + @Configuration + static class AnnotationSessionFactoryConfig extends DataConfig { + @Bean + SessionFactory sessionFactory() throws Exception { + return new AnnotationSessionFactoryBuilder(dataSource()) + .setSchemaUpdate(true) + .doWithConfiguration(new HibernateConfigurationCallback() { + public void configure(AnnotationConfiguration configuration) { + configuration.addAnnotatedClass(Foo.class); + } + }) + .buildSessionFactory(); + } + } + + + @Configuration + static class AnnotationSessionFactoryConfig_withPackagesToScan extends DataConfig { + @Bean + SessionFactory sessionFactory() throws Exception { + return new AnnotationSessionFactoryBuilder(dataSource()) + .setSchemaUpdate(true) + .setPackagesToScan(Foo.class.getPackage().getName()) + .buildSessionFactory(); + } + } + + @Configuration + static class AnnotationSessionFactoryConfig_withAnnotatedClasses extends DataConfig { + @Bean + SessionFactory sessionFactory() throws Exception { + return new AnnotationSessionFactoryBuilder(dataSource()) + .setSchemaUpdate(true) + .setAnnotatedClasses(Foo.class, Foo.class) + .buildSessionFactory(); + } + } + + + @Configuration + static class AnnotationSessionFactoryConfig_withConfigurationCallback extends DataConfig { + @Bean + SessionFactory sessionFactory() throws Exception { + return new AnnotationSessionFactoryBuilder(dataSource()) + .setSchemaUpdate(true) + .doWithConfiguration(new HibernateConfigurationCallback() { + public void configure(AnnotationConfiguration configuration) throws Exception { + configuration.addAnnotatedClass(Foo.class); + } + }) + .buildSessionFactory(); + } + } + + + @Configuration + static class SessionFactoryConfig_withConfigurationCallback extends DataConfig { + @Bean + SessionFactory sessionFactory() throws Exception { + return new SessionFactoryBuilder(dataSource()) + .setSchemaUpdate(true) + .doWithConfiguration(new HibernateConfigurationCallback() { + public void configure(org.hibernate.cfg.Configuration configuration) throws Exception { + configuration.addFile(new File(this.getClass().getClassLoader().getResource("org/springframework/orm/hibernate3/scannable/FooMapping.hbm.xml").toURI())); + } + }) + .buildSessionFactory(); + } + } + + + @Configuration + static class SessionFactoryConfig_withCustomConfigurationClass extends DataConfig { + @Bean + SessionFactory sessionFactory() throws Exception { + SessionFactoryBuilder sfb = new SessionFactoryBuilder(dataSource()) + .setSchemaUpdate(true) + .setConfigurationClass(CustomHibernateConfiguration.class) + .doWithConfiguration(new HibernateConfigurationCallback() { + public void configure(org.hibernate.cfg.Configuration configuration) throws Exception { + configuration.addFile(new File(this.getClass().getClassLoader().getResource("org/springframework/orm/hibernate3/scannable/FooMapping.hbm.xml").toURI())); + } + }); + assertThat(sfb.getConfiguration(), instanceOf(CustomHibernateConfiguration.class)); + return sfb.buildSessionFactory(); + } + } + + + @Configuration + static class SessionFactoryConfig_withLateCustomConfigurationClass extends DataConfig { + @Bean + SessionFactory sessionFactory() throws Exception { + return new SessionFactoryBuilder(dataSource()) + .setSchemaUpdate(true) + .doWithConfiguration(new HibernateConfigurationCallback() { + public void configure(org.hibernate.cfg.Configuration configuration) throws Exception { + configuration.addFile(new File(this.getClass().getClassLoader().getResource("org/springframework/orm/hibernate3/scannable/FooMapping.hbm.xml").toURI())); + } + }) + .setConfigurationClass(CustomHibernateConfiguration.class) + .buildSessionFactory(); + } + } + + + @SuppressWarnings("serial") + static class CustomHibernateConfiguration extends org.hibernate.cfg.Configuration { + } + +} diff --git a/org.springframework.integration-tests/src/test/java/org/springframework/orm/hibernate3/scannable/Foo.java b/org.springframework.integration-tests/src/test/java/org/springframework/orm/hibernate3/scannable/Foo.java new file mode 100644 index 00000000000..0728499b09f --- /dev/null +++ b/org.springframework.integration-tests/src/test/java/org/springframework/orm/hibernate3/scannable/Foo.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2011 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.scannable; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Foo { + @SuppressWarnings("unused") + @Id private int id; + + private String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } +} \ No newline at end of file diff --git a/org.springframework.integration-tests/src/test/resources/org/springframework/orm/hibernate3/AnnotationSessionFactoryBeanXmlConfig-context.xml b/org.springframework.integration-tests/src/test/resources/org/springframework/orm/hibernate3/AnnotationSessionFactoryBeanXmlConfig-context.xml new file mode 100644 index 00000000000..dd5ec1d94c8 --- /dev/null +++ b/org.springframework.integration-tests/src/test/resources/org/springframework/orm/hibernate3/AnnotationSessionFactoryBeanXmlConfig-context.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/org.springframework.integration-tests/src/test/resources/org/springframework/orm/hibernate3/LocalSessionFactoryBeanXmlConfig-context.xml b/org.springframework.integration-tests/src/test/resources/org/springframework/orm/hibernate3/LocalSessionFactoryBeanXmlConfig-context.xml new file mode 100644 index 00000000000..c3a2f30b314 --- /dev/null +++ b/org.springframework.integration-tests/src/test/resources/org/springframework/orm/hibernate3/LocalSessionFactoryBeanXmlConfig-context.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + hibernate.dialect=org.hibernate.dialect.HSQLDialect + + + + + \ No newline at end of file diff --git a/org.springframework.integration-tests/src/test/resources/org/springframework/orm/hibernate3/scannable/FooMapping.hbm.xml b/org.springframework.integration-tests/src/test/resources/org/springframework/orm/hibernate3/scannable/FooMapping.hbm.xml new file mode 100644 index 00000000000..187f1452184 --- /dev/null +++ b/org.springframework.integration-tests/src/test/resources/org/springframework/orm/hibernate3/scannable/FooMapping.hbm.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/AbstractSessionFactoryBean.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/AbstractSessionFactoryBean.java deleted file mode 100644 index 135538e7953..00000000000 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/AbstractSessionFactoryBean.java +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2002-2010 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 javax.sql.DataSource; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.HibernateException; -import org.hibernate.JDBCException; -import org.hibernate.SessionFactory; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.support.PersistenceExceptionTranslator; -import org.springframework.jdbc.support.SQLExceptionTranslator; - -/** - * Abstract {@link org.springframework.beans.factory.FactoryBean} that creates - * a Hibernate {@link org.hibernate.SessionFactory} within a Spring application - * context, providing general infrastructure not related to Hibernate's - * specific configuration API. - * - *

This class implements the - * {@link org.springframework.dao.support.PersistenceExceptionTranslator} - * interface, as autodetected by Spring's - * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor}, - * for AOP-based translation of native exceptions to Spring DataAccessExceptions. - * Hence, the presence of e.g. LocalSessionFactoryBean automatically enables - * a PersistenceExceptionTranslationPostProcessor to translate Hibernate exceptions. - * - *

This class mainly serves as common base class for {@link LocalSessionFactoryBean}. - * For details on typical SessionFactory setup, see the LocalSessionFactoryBean javadoc. - * - * @author Juergen Hoeller - * @since 2.0 - * @see #setExposeTransactionAwareSessionFactory - * @see org.hibernate.SessionFactory#getCurrentSession() - * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor - */ -public abstract class AbstractSessionFactoryBean - implements FactoryBean, InitializingBean, DisposableBean, PersistenceExceptionTranslator { - - /** Logger available to subclasses */ - protected final Log logger = LogFactory.getLog(getClass()); - - private DataSource dataSource; - - private boolean useTransactionAwareDataSource = false; - - private boolean exposeTransactionAwareSessionFactory = true; - - private SQLExceptionTranslator jdbcExceptionTranslator; - - private SessionFactory sessionFactory; - - - /** - * Set the DataSource to be used by the SessionFactory. - * If set, this will override corresponding settings in Hibernate properties. - *

If this is set, the Hibernate settings should not define - * a connection provider to avoid meaningless double configuration. - *

If using HibernateTransactionManager as transaction strategy, consider - * proxying your target DataSource with a LazyConnectionDataSourceProxy. - * This defers fetching of an actual JDBC Connection until the first JDBC - * Statement gets executed, even within JDBC transactions (as performed by - * HibernateTransactionManager). Such lazy fetching is particularly beneficial - * for read-only operations, in particular if the chances of resolving the - * result in the second-level cache are high. - *

As JTA and transactional JNDI DataSources already provide lazy enlistment - * of JDBC Connections, LazyConnectionDataSourceProxy does not add value with - * JTA (i.e. Spring's JtaTransactionManager) as transaction strategy. - * @see #setUseTransactionAwareDataSource - * @see HibernateTransactionManager - * @see org.springframework.transaction.jta.JtaTransactionManager - * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy - */ - public void setDataSource(DataSource dataSource) { - this.dataSource = dataSource; - } - - /** - * Return the DataSource to be used by the SessionFactory. - */ - public DataSource getDataSource() { - return this.dataSource; - } - - /** - * Set whether to use a transaction-aware DataSource for the SessionFactory, - * i.e. whether to automatically wrap the passed-in DataSource with Spring's - * TransactionAwareDataSourceProxy. - *

Default is "false": LocalSessionFactoryBean is usually used with Spring's - * HibernateTransactionManager or JtaTransactionManager, both of which work nicely - * on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are - * fully managed by the Hibernate/JTA transaction infrastructure in such a scenario. - *

If you switch this flag to "true", Spring's Hibernate access will be able to - * participate in JDBC-based transactions managed outside of Hibernate - * (for example, by Spring's DataSourceTransactionManager). This can be convenient - * if you need a different local transaction strategy for another O/R mapping tool, - * for example, but still want Hibernate access to join into those transactions. - *

A further benefit of this option is that plain Sessions opened directly - * via the SessionFactory, outside of Spring's Hibernate support, will still - * participate in active Spring-managed transactions. However, consider using - * Hibernate's getCurrentSession() method instead (see javadoc of - * "exposeTransactionAwareSessionFactory" property). - *

WARNING: When using a transaction-aware JDBC DataSource in combination - * with OpenSessionInViewFilter/Interceptor, whether participating in JTA or - * external JDBC-based transactions, it is strongly recommended to set Hibernate's - * Connection release mode to "after_transaction" or "after_statement", which - * guarantees proper Connection handling in such a scenario. In contrast to that, - * HibernateTransactionManager generally requires release mode "on_close". - *

Note: If you want to use Hibernate's Connection release mode "after_statement" - * with a DataSource specified on this LocalSessionFactoryBean (for example, a - * JTA-aware DataSource fetched from JNDI), switch this setting to "true". - * Otherwise, the ConnectionProvider used underneath will vote against aggressive - * release and thus silently switch to release mode "after_transaction". - * @see #setDataSource - * @see #setExposeTransactionAwareSessionFactory - * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy - * @see org.springframework.jdbc.datasource.DataSourceTransactionManager - * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter - * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor - * @see HibernateTransactionManager - * @see org.springframework.transaction.jta.JtaTransactionManager - */ - public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) { - this.useTransactionAwareDataSource = useTransactionAwareDataSource; - } - - /** - * Return whether to use a transaction-aware DataSource for the SessionFactory. - */ - protected boolean isUseTransactionAwareDataSource() { - return this.useTransactionAwareDataSource; - } - - /** - * Set whether to expose a transaction-aware current Session from the - * SessionFactory's getCurrentSession() method, returning the - * Session that's associated with the current Spring-managed transaction, if any. - *

Default is "true", letting data access code work with the plain - * Hibernate SessionFactory and its getCurrentSession() method, - * while still being able to participate in current Spring-managed transactions: - * with any transaction management strategy, either local or JTA / EJB CMT, - * and any transaction synchronization mechanism, either Spring or JTA. - * Furthermore, getCurrentSession() will also seamlessly work with - * a request-scoped Session managed by OpenSessionInViewFilter/Interceptor. - *

Turn this flag off to expose the plain Hibernate SessionFactory with - * Hibernate's default getCurrentSession() behavior, supporting - * plain JTA synchronization only. Alternatively, simply override the - * corresponding Hibernate property "hibernate.current_session_context_class". - * @see SpringSessionContext - * @see org.hibernate.SessionFactory#getCurrentSession() - * @see org.springframework.transaction.jta.JtaTransactionManager - * @see HibernateTransactionManager - * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter - * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor - */ - public void setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) { - this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory; - } - - /** - * Return whether to expose a transaction-aware proxy for the SessionFactory. - */ - protected boolean isExposeTransactionAwareSessionFactory() { - return this.exposeTransactionAwareSessionFactory; - } - - /** - * Set the JDBC exception translator for the SessionFactory, - * exposed via the PersistenceExceptionTranslator interface. - *

Applied to any SQLException root cause of a Hibernate JDBCException, - * overriding Hibernate's default SQLException translation (which is - * based on Hibernate's Dialect for a specific target database). - * @param jdbcExceptionTranslator the exception translator - * @see java.sql.SQLException - * @see org.hibernate.JDBCException - * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator - * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator - * @see org.springframework.dao.support.PersistenceExceptionTranslator - */ - public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) { - this.jdbcExceptionTranslator = jdbcExceptionTranslator; - } - - - /** - * Build and expose the SessionFactory. - * @see #buildSessionFactory() - * @see #wrapSessionFactoryIfNecessary - */ - public void afterPropertiesSet() throws Exception { - SessionFactory rawSf = buildSessionFactory(); - this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf); - afterSessionFactoryCreation(); - } - - /** - * Wrap the given SessionFactory with a proxy, if demanded. - *

The default implementation simply returns the given SessionFactory as-is. - * Subclasses may override this to implement transaction awareness through - * a SessionFactory proxy, for example. - * @param rawSf the raw SessionFactory as built by {@link #buildSessionFactory()} - * @return the SessionFactory reference to expose - * @see #buildSessionFactory() - */ - protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) { - return rawSf; - } - - /** - * Return the exposed SessionFactory. - * Will throw an exception if not initialized yet. - * @return the SessionFactory (never null) - * @throws IllegalStateException if the SessionFactory has not been initialized yet - */ - protected final SessionFactory getSessionFactory() { - if (this.sessionFactory == null) { - throw new IllegalStateException("SessionFactory not initialized yet"); - } - return this.sessionFactory; - } - - /** - * Close the SessionFactory on bean factory shutdown. - */ - public void destroy() throws HibernateException { - logger.info("Closing Hibernate SessionFactory"); - try { - beforeSessionFactoryDestruction(); - } - finally { - this.sessionFactory.close(); - } - } - - - /** - * Return the singleton SessionFactory. - */ - public SessionFactory getObject() { - return this.sessionFactory; - } - - public Class getObjectType() { - return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class); - } - - public boolean isSingleton() { - return true; - } - - - /** - * Implementation of the PersistenceExceptionTranslator interface, - * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor. - *

Converts the exception if it is a HibernateException; - * else returns null to indicate an unknown exception. - * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor - * @see #convertHibernateAccessException - */ - public DataAccessException translateExceptionIfPossible(RuntimeException ex) { - if (ex instanceof HibernateException) { - return convertHibernateAccessException((HibernateException) ex); - } - return null; - } - - /** - * Convert the given HibernateException to an appropriate exception from the - * org.springframework.dao hierarchy. - *

Will automatically apply a specified SQLExceptionTranslator to a - * Hibernate JDBCException, else rely on Hibernate's default translation. - * @param ex HibernateException that occured - * @return a corresponding DataAccessException - * @see SessionFactoryUtils#convertHibernateAccessException - * @see #setJdbcExceptionTranslator - */ - protected DataAccessException convertHibernateAccessException(HibernateException ex) { - if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException) { - JDBCException jdbcEx = (JDBCException) ex; - return this.jdbcExceptionTranslator.translate( - "Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException()); - } - return SessionFactoryUtils.convertHibernateAccessException(ex); - } - - - /** - * Build the underlying Hibernate SessionFactory. - * @return the raw SessionFactory (potentially to be wrapped with a - * transaction-aware proxy before it is exposed to the application) - * @throws Exception in case of initialization failure - */ - protected abstract SessionFactory buildSessionFactory() throws Exception; - - /** - * Hook that allows post-processing after the SessionFactory has been - * successfully created. The SessionFactory is already available through - * getSessionFactory() at this point. - *

This implementation is empty. - * @throws Exception in case of initialization failure - * @see #getSessionFactory() - */ - protected void afterSessionFactoryCreation() throws Exception { - } - - /** - * Hook that allows shutdown processing before the SessionFactory - * will be closed. The SessionFactory is still available through - * getSessionFactory() at this point. - *

This implementation is empty. - * @see #getSessionFactory() - */ - protected void beforeSessionFactoryDestruction() { - } - -} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/FilterDefinitionFactoryBean.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/FilterDefinitionFactoryBean.java index 04b7789d3b8..3f84727aa01 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/FilterDefinitionFactoryBean.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/FilterDefinitionFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2011 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. @@ -37,24 +37,25 @@ import org.springframework.util.ReflectionUtils; * definition, as the list element for the "filterDefinitions" bean property. * For example: * - *

- * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
+ * 
+ * {@code
+ * 
  *   ...
- *   <property name="filterDefinitions">
- *     <list>
- *       <bean class="org.springframework.orm.hibernate3.FilterDefinitionFactoryBean">
- *         <property name="filterName" value="myFilter"/>
- *         <property name="parameterTypes">
- *           <map>
- *             <entry key="myParam" value="string"/>
- *             <entry key="myOtherParam" value="long"/>
- *           </map>
- *         </property>
- *       </bean>
- *     </list>
- *   </property>
+ *   
+ *     
+ *       
+ *         
+ *         
+ *           
+ *             
+ *             
+ *           
+ *         
+ *       
+ *     
+ *   
  *   ...
- * </bean>
+ * }
* * Alternatively, specify a bean id (or name) attribute for the inner bean, * instead of the "filterName" property. @@ -73,7 +74,7 @@ public class FilterDefinitionFactoryBean implements FactoryBean trClass = FilterDefinitionFactoryBean.class.getClassLoader().loadClass( "org.hibernate.type.TypeResolver"); heuristicTypeMethod = trClass.getMethod("heuristicType", String.class); typeResolver = trClass.newInstance(); diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateAccessor.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateAccessor.java index 7fe337d6595..7b3b4e05a3b 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateAccessor.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateAccessor.java @@ -181,12 +181,13 @@ public abstract class HibernateAccessor implements InitializingBean, BeanFactory * property values before writing to and reading from the database. * Will get applied to any new Session created by this object. *

Such an interceptor can either be set at the SessionFactory level, - * i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on - * HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. - * It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager - * to avoid repeated configuration and guarantee consistent behavior in transactions. + * i.e. on SessionFactoryBuilder/LocalSessionFactoryBean, or at the Session + * level, i.e. on HibernateTemplate, HibernateInterceptor, and + * HibernateTransactionManager. It's preferable to set it on + * SessionFactoryBuilder or HibernateTransactionManager to avoid repeated + * configuration and guarantee consistent behavior in transactions. * @see #setEntityInterceptorBeanName - * @see LocalSessionFactoryBean#setEntityInterceptor + * @see SessionFactoryBuilder#setEntityInterceptor * @see HibernateTransactionManager#setEntityInterceptor */ public void setEntityInterceptor(Interceptor entityInterceptor) { @@ -208,7 +209,7 @@ public abstract class HibernateAccessor implements InitializingBean, BeanFactory if (this.beanFactory == null) { throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set"); } - return (Interceptor) this.beanFactory.getBean((String) this.entityInterceptor, Interceptor.class); + return this.beanFactory.getBean((String) this.entityInterceptor, Interceptor.class); } return (Interceptor) this.entityInterceptor; } @@ -272,7 +273,7 @@ public abstract class HibernateAccessor implements InitializingBean, BeanFactory * Sessions (for example, within a transaction). * @see #enableFilters(org.hibernate.Session) * @see org.hibernate.Session#enableFilter(String) - * @see LocalSessionFactoryBean#setFilterDefinitions + * @see SessionFactoryBuilder#setFilterDefinitions */ public void setFilterName(String filter) { this.filterNames = new String[] {filter}; @@ -287,7 +288,7 @@ public abstract class HibernateAccessor implements InitializingBean, BeanFactory * Sessions (for example, within a transaction). * @see #enableFilters(org.hibernate.Session) * @see org.hibernate.Session#enableFilter(String) - * @see LocalSessionFactoryBean#setFilterDefinitions + * @see SessionFactoryBuilder#setFilterDefinitions */ public void setFilterNames(String[] filterNames) { this.filterNames = filterNames; diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateConfigurationCallback.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateConfigurationCallback.java new file mode 100644 index 00000000000..1099d1894da --- /dev/null +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateConfigurationCallback.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2011 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.hibernate.cfg.Configuration; + +/** + * Callback for use in conjunction with {@link SessionFactoryBuilderSupport#doWithConfiguration}. + * + * @author Chris Beams + * @since 3.1 + * @see SessionFactoryBuilderSupport#doWithConfiguration + * @see SessionFactoryBuilder + * @see org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBuilder + */ +public interface HibernateConfigurationCallback { + + /** + * Configure the given Hibernate {@code Configuration type}. Note that methods + * only setter methods should be called, and methods such as + * {@link Configuration#buildSessionFactory()} should be avoided. + * @throws Exception to propagate any exception thrown by + * {@code Configuration} methods + */ + void configure(C configuration) throws Exception; + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateTemplate.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateTemplate.java index 72962e4087f..d8d0a542040 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateTemplate.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2011 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. @@ -40,7 +40,6 @@ import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.Example; import org.hibernate.engine.SessionImplementor; import org.hibernate.event.EventSource; - import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -77,10 +76,10 @@ import org.springframework.util.Assert; * management, not participating in a custom Hibernate CurrentSessionContext * unless you explicitly switch {@link #setAllowCreate "allowCreate"} to "false". * - *

{@link LocalSessionFactoryBean} is the preferred way of obtaining a reference - * to a specific Hibernate SessionFactory, at least in a non-EJB environment. - * The Spring application context will manage its lifecycle, initializing and - * shutting down the factory as part of the application. + *

Using a {@link SessionFactoryBuilder} is the preferred way of obtaining a + * reference to a specific Hibernate SessionFactory, at least in a non-EJB + * environment. The Spring application context will manage its lifecycle, + * initializing and shutting down the factory as part of the application. * *

Note that operations that return an Iterator (i.e. iterate) * are supposed to be used within Spring-driven or JTA-driven transactions @@ -99,7 +98,7 @@ import org.springframework.util.Assert; * @see #setSessionFactory * @see HibernateCallback * @see org.hibernate.Session - * @see LocalSessionFactoryBean + * @see SessionFactoryBuilder * @see HibernateTransactionManager * @see org.springframework.transaction.jta.JtaTransactionManager * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateTransactionManager.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateTransactionManager.java index ae5f3853b3c..d0910264d99 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateTransactionManager.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/HibernateTransactionManager.java @@ -80,8 +80,9 @@ import org.springframework.transaction.support.TransactionSynchronizationManager * this instance needs to be aware of the DataSource ({@link #setDataSource}). * The given DataSource should obviously match the one used by the given * SessionFactory. To achieve this, configure both to the same JNDI DataSource, - * or preferably create the SessionFactory with {@link LocalSessionFactoryBean} and - * a local DataSource (which will be autodetected by this transaction manager). + * or preferably create the SessionFactory with {@link SessionFactoryBuilder} / + * {@link LocalSessionFactoryBean} and a local DataSource (which will be + * autodetected by this transaction manager). * *

JTA (usually through {@link org.springframework.transaction.jta.JtaTransactionManager}) * is necessary for accessing multiple transactional resources within the same @@ -116,6 +117,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager * @since 1.2 * @see #setSessionFactory * @see #setDataSource + * @see SessionFactoryBuilder * @see LocalSessionFactoryBean * @see SessionFactoryUtils#getSession * @see SessionFactoryUtils#applyTransactionTimeout @@ -129,6 +131,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager * @see org.springframework.jdbc.datasource.DataSourceTransactionManager * @see org.springframework.transaction.jta.JtaTransactionManager */ +@SuppressWarnings("serial") public class HibernateTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, BeanFactoryAware, InitializingBean { @@ -194,7 +197,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana * The DataSource should match the one used by the Hibernate SessionFactory: * for example, you could specify the same JNDI DataSource for both. *

If the SessionFactory was configured with LocalDataSourceConnectionProvider, - * i.e. by Spring's LocalSessionFactoryBean with a specified "dataSource", + * i.e. by Spring's SessionFactoryBuilder with a specified "dataSource", * the DataSource will be auto-detected: You can still explictly specify the * DataSource, but you don't need to in this case. *

A transactional JDBC Connection for this DataSource will be provided to @@ -208,7 +211,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana * unwrapped to extract its target DataSource. * @see #setAutodetectDataSource * @see LocalDataSourceConnectionProvider - * @see LocalSessionFactoryBean#setDataSource + * @see SessionFactoryBuilder#setDataSource * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy * @see org.springframework.jdbc.datasource.DataSourceUtils * @see org.springframework.jdbc.core.JdbcTemplate @@ -234,11 +237,11 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana /** * Set whether to autodetect a JDBC DataSource used by the Hibernate SessionFactory, - * if set via LocalSessionFactoryBean's setDataSource. Default is "true". + * if set via SessionFactoryBuilder's setDataSource. Default is "true". *

Can be turned off to deliberately ignore an available DataSource, in order * to not expose Hibernate transactions as JDBC transactions for that DataSource. * @see #setDataSource - * @see LocalSessionFactoryBean#setDataSource + * @see SessionFactoryBuilder#setDataSource */ public void setAutodetectDataSource(boolean autodetectDataSource) { this.autodetectDataSource = autodetectDataSource; @@ -329,11 +332,11 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana * property values before writing to and reading from the database. * Will get applied to any new Session created by this transaction manager. *

Such an interceptor can either be set at the SessionFactory level, - * i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on + * i.e. on SessionFactoryBuilder, or at the Session level, i.e. on * HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager. - * It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager + * It's preferable to set it on SessionFactoryBuilder or HibernateTransactionManager * to avoid repeated configuration and guarantee consistent behavior in transactions. - * @see LocalSessionFactoryBean#setEntityInterceptor + * @see SessionFactoryBuilder#setEntityInterceptor * @see HibernateTemplate#setEntityInterceptor * @see HibernateInterceptor#setEntityInterceptor */ @@ -504,6 +507,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana logger.debug( "Preparing JDBC Connection of Hibernate Session [" + SessionFactoryUtils.toString(session) + "]"); } + @SuppressWarnings("deprecation") Connection con = session.connection(); Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition); txObject.setPreviousIsolationLevel(previousIsolationLevel); @@ -516,7 +520,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana "HibernateTransactionManager is not allowed to support custom isolation levels: " + "make sure that its 'prepareConnection' flag is on (the default) and that the " + "Hibernate connection release mode is set to 'on_close' (SpringTransactionFactory's default). " + - "Make sure that your LocalSessionFactoryBean actually uses SpringTransactionFactory: Your " + + "Make sure that your SessionFactoryBuilder actually uses SpringTransactionFactory: Your " + "Hibernate properties should *not* include a 'hibernate.transaction.factory_class' property!"); } if (logger.isDebugEnabled()) { @@ -560,6 +564,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana // Register the Hibernate Session's JDBC Connection for the DataSource, if set. if (getDataSource() != null) { + @SuppressWarnings("deprecation") Connection con = session.connection(); ConnectionHolder conHolder = new ConnectionHolder(con); if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { @@ -721,6 +726,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana // the isolation level and/or read-only flag of the JDBC Connection here. // Else, we need to rely on the connection pool to perform proper cleanup. try { + @SuppressWarnings("deprecation") Connection con = session.connection(); DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel()); } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalCacheProviderProxy.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalCacheProviderProxy.java index e240800e0f3..bc9c6a906c8 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalCacheProviderProxy.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalCacheProviderProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2011 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. @@ -28,16 +28,23 @@ import org.hibernate.cache.CacheProvider; * "cacheProvider" property. * * @author Juergen Hoeller + * @author Chris Beams * @since 2.5.1 * @see LocalSessionFactoryBean#setCacheProvider + * @see LocalRegionFactoryProxy + * @deprecated as of Spring 3.1 to reflect the deprecation of the + * CacheProvider SPI in Hibernate 3.3. Favor the new + * {@link org.hibernate.cache.RegionFactory} SPI and Spring's + * {@link LocalRegionFactoryProxy} support. */ +@Deprecated public class LocalCacheProviderProxy implements CacheProvider { private final CacheProvider cacheProvider; public LocalCacheProviderProxy() { - CacheProvider cp = LocalSessionFactoryBean.getConfigTimeCacheProvider(); + CacheProvider cp = SessionFactoryBeanDelegate.getConfigTimeCacheProvider(); // absolutely needs thread-bound CacheProvider to initialize if (cp == null) { throw new IllegalStateException("No Hibernate CacheProvider found - " + diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalDataSourceConnectionProvider.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalDataSourceConnectionProvider.java index 29a711b3337..0af65601b1b 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalDataSourceConnectionProvider.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalDataSourceConnectionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2011 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. @@ -19,6 +19,7 @@ package org.springframework.orm.hibernate3; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; + import javax.sql.DataSource; import org.hibernate.HibernateException; @@ -28,12 +29,12 @@ import org.hibernate.util.JDBCExceptionReporter; /** * Hibernate connection provider for local DataSource instances * in an application context. This provider will be used if - * LocalSessionFactoryBean's "dataSource" property is set + * SessionFactoryBuilder's "dataSource" property is set * without a Hibernate TransactionManagerLookup. * * @author Juergen Hoeller * @since 1.2 - * @see LocalSessionFactoryBean#setDataSource + * @see SessionFactoryBuilder#setDataSource */ public class LocalDataSourceConnectionProvider implements ConnectionProvider { @@ -43,11 +44,11 @@ public class LocalDataSourceConnectionProvider implements ConnectionProvider { public void configure(Properties props) throws HibernateException { - this.dataSource = LocalSessionFactoryBean.getConfigTimeDataSource(); + this.dataSource = SessionFactoryBuilderSupport.getConfigTimeDataSource(); // absolutely needs thread-bound DataSource to initialize if (this.dataSource == null) { throw new HibernateException("No local DataSource found for configuration - " + - "'dataSource' property must be set on LocalSessionFactoryBean"); + "'dataSource' property must be set on SessionFactoryBuilder"); } this.dataSourceToUse = getDataSourceToUse(this.dataSource); } @@ -56,10 +57,10 @@ public class LocalDataSourceConnectionProvider implements ConnectionProvider { * Return the DataSource to use for retrieving Connections. *

This implementation returns the passed-in DataSource as-is. * @param originalDataSource the DataSource as configured by the user - * on LocalSessionFactoryBean + * on SessionFactoryBuilder * @return the DataSource to actually retrieve Connections from * (potentially wrapped) - * @see LocalSessionFactoryBean#setDataSource + * @see SessionFactoryBuilder#setDataSource */ protected DataSource getDataSourceToUse(DataSource originalDataSource) { return originalDataSource; diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalJtaDataSourceConnectionProvider.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalJtaDataSourceConnectionProvider.java index b2da29349e9..c4f204d0aa7 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalJtaDataSourceConnectionProvider.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalJtaDataSourceConnectionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2011 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. @@ -18,7 +18,7 @@ package org.springframework.orm.hibernate3; /** * Subclass of LocalDataSourceConnectionProvider that will be used - * if LocalSessionFactoryBean's "dataSource" property is set + * if SessionFactoryBean's "dataSource" property is set * in combination with a Hibernate TransactionManagerLookup. * * @author Juergen Hoeller diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalRegionFactoryProxy.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalRegionFactoryProxy.java index d43196ce3fb..6e3c1d5b717 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalRegionFactoryProxy.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalRegionFactoryProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2011 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. @@ -33,7 +33,7 @@ import org.springframework.util.ReflectionUtils; /** * Proxy for a Hibernate RegionFactory, delegating to a Spring-managed - * RegionFactory instance, determined by LocalSessionFactoryBean's + * RegionFactory instance, determined by SessionFactoryBuilder's * "cacheRegionFactory" property. * *

Compatible with Hibernate 3.3 as well as Hibernate 3.5's version @@ -41,7 +41,7 @@ import org.springframework.util.ReflectionUtils; * * @author Juergen Hoeller * @since 3.0 - * @see LocalSessionFactoryBean#setCacheRegionFactory + * @see SessionFactoryBuilder#setCacheRegionFactory */ public class LocalRegionFactoryProxy implements RegionFactory { @@ -52,11 +52,11 @@ public class LocalRegionFactoryProxy implements RegionFactory { * Standard constructor. */ public LocalRegionFactoryProxy() { - RegionFactory rf = (RegionFactory) LocalSessionFactoryBean.getConfigTimeRegionFactory(); + RegionFactory rf = (RegionFactory) SessionFactoryBuilderSupport.getConfigTimeRegionFactory(); // absolutely needs thread-bound RegionFactory to initialize if (rf == null) { throw new IllegalStateException("No Hibernate RegionFactory found - " + - "'cacheRegionFactory' property must be set on LocalSessionFactoryBean"); + "'cacheRegionFactory' property must be set on SessionFactoryBuilder"); } this.regionFactory = rf; } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalSessionFactoryBean.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalSessionFactoryBean.java index 0cb0d7335f1..40786470aba 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalSessionFactoryBean.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalSessionFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2011 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. @@ -16,1109 +16,125 @@ package org.springframework.orm.hibernate3; -import java.io.File; -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Collection; -import java.util.Enumeration; -import java.util.Map; -import java.util.Properties; -import javax.sql.DataSource; -import javax.transaction.TransactionManager; - import org.hibernate.HibernateException; -import org.hibernate.Interceptor; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.cache.CacheProvider; -import org.hibernate.cfg.Configuration; -import org.hibernate.cfg.Environment; -import org.hibernate.cfg.NamingStrategy; -import org.hibernate.dialect.Dialect; -import org.hibernate.engine.FilterDefinition; -import org.hibernate.event.EventListeners; -import org.hibernate.tool.hbm2ddl.DatabaseMetadata; -import org.hibernate.transaction.JTATransactionFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; +import org.hibernate.SessionFactory; import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; -import org.springframework.jdbc.support.JdbcUtils; -import org.springframework.jdbc.support.lob.LobHandler; -import org.springframework.util.ClassUtils; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; +import org.springframework.jdbc.support.SQLExceptionTranslator; /** - * {@link org.springframework.beans.factory.FactoryBean} that creates a - * Hibernate {@link org.hibernate.SessionFactory}. This is the usual way to - * set up a shared Hibernate SessionFactory in a Spring application context; - * the SessionFactory can then be passed to Hibernate-based DAOs via - * dependency injection. - * - *

Configuration settings can either be read from a Hibernate XML file, - * specified as "configLocation", or completely via this class. A typical - * local configuration consists of one or more "mappingResources", various - * "hibernateProperties" (not strictly necessary), and a "dataSource" that the - * SessionFactory should use. The latter can also be specified via Hibernate - * properties, but "dataSource" supports any Spring-configured DataSource, - * instead of relying on Hibernate's own connection providers. + * Subclass of {@link SessionFactoryBuilder} adhering to Spring's + * {@link org.springframework.beans.factory.FactoryBean FactoryBean} contract, + * making it suitable for use in XML configuration. * - *

This SessionFactory handling strategy is appropriate for most types of - * applications, from Hibernate-only single database apps to ones that need - * distributed transactions. Either {@link HibernateTransactionManager} or - * {@link org.springframework.transaction.jta.JtaTransactionManager} can be - * used for transaction demarcation, with the latter only necessary for - * transactions which span multiple databases. + *

A typical {@code LocalSessionFactoryBean} bean definition: * - *

This factory bean will by default expose a transaction-aware SessionFactory - * proxy, letting data access code work with the plain Hibernate SessionFactory - * and its getCurrentSession() method, while still being able to - * participate in current Spring-managed transactions: with any transaction - * management strategy, either local or JTA / EJB CMT, and any transaction - * synchronization mechanism, either Spring or JTA. Furthermore, - * getCurrentSession() will also seamlessly work with - * a request-scoped Session managed by - * {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter} / - * {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}. + *

+ * {@code
+ * 
+ *   
+ *   
+ * }
* - *

Requires Hibernate 3.2 or later; tested with 3.3, 3.5 and 3.6. - * Note that this factory will use "on_close" as default Hibernate connection - * release mode, unless in the case of a "jtaTransactionManager" specified, - * for the reason that this is appropriate for most Spring-based applications - * (in particular when using Spring's HibernateTransactionManager). + *

Implements the + * {@link org.springframework.dao.support.PersistenceExceptionTranslator + * PersistenceExceptionTranslator} interface, as autodetected by Spring's {@link + * org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor + * PersistenceExceptionTranslationPostProcessor}, for AOP-based translation of + * native Hibernate exceptions to Spring's {@link DataAccessException} hierarchy. + * Hence, the presence of an {@code LocalSessionFactoryBean} automatically + * enables a {@code PersistenceExceptionTranslationPostProcessor} to translate + * Hibernate exceptions. * * @author Juergen Hoeller + * @author Chris Beams * @since 1.2 - * @see HibernateTemplate#setSessionFactory - * @see HibernateTransactionManager#setSessionFactory - * @see #setExposeTransactionAwareSessionFactory - * @see #setJtaTransactionManager - * @see org.hibernate.SessionFactory#getCurrentSession() - * @see HibernateTransactionManager + * @see SessionFactoryBuilderSupport + * @see SessionFactoryBeanOperations + * @see org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean */ -public class LocalSessionFactoryBean extends AbstractSessionFactoryBean implements BeanClassLoaderAware { - - private static final ThreadLocal configTimeDataSourceHolder = - new ThreadLocal(); - - private static final ThreadLocal configTimeTransactionManagerHolder = - new ThreadLocal(); - - private static final ThreadLocal configTimeRegionFactoryHolder = - new ThreadLocal(); - - private static final ThreadLocal configTimeCacheProviderHolder = - new ThreadLocal(); - - private static final ThreadLocal configTimeLobHandlerHolder = - new ThreadLocal(); - - /** - * Return the DataSource for the currently configured Hibernate SessionFactory, - * to be used by LocalDataSourceConnectionProvoder. - *

This instance will be set before initialization of the corresponding - * SessionFactory, and reset immediately afterwards. It is thus only available - * during configuration. - * @see #setDataSource - * @see LocalDataSourceConnectionProvider - */ - public static DataSource getConfigTimeDataSource() { - return configTimeDataSourceHolder.get(); - } - - /** - * Return the JTA TransactionManager for the currently configured Hibernate - * SessionFactory, to be used by LocalTransactionManagerLookup. - *

This instance will be set before initialization of the corresponding - * SessionFactory, and reset immediately afterwards. It is thus only available - * during configuration. - * @see #setJtaTransactionManager - * @see LocalTransactionManagerLookup - */ - public static TransactionManager getConfigTimeTransactionManager() { - return configTimeTransactionManagerHolder.get(); - } - - /** - * Return the RegionFactory for the currently configured Hibernate SessionFactory, - * to be used by LocalRegionFactoryProxy. - *

This instance will be set before initialization of the corresponding - * SessionFactory, and reset immediately afterwards. It is thus only available - * during configuration. - * @see #setCacheRegionFactory - */ - static Object getConfigTimeRegionFactory() { - return configTimeRegionFactoryHolder.get(); - } - - /** - * Return the CacheProvider for the currently configured Hibernate SessionFactory, - * to be used by LocalCacheProviderProxy. - *

This instance will be set before initialization of the corresponding - * SessionFactory, and reset immediately afterwards. It is thus only available - * during configuration. - * @see #setCacheProvider - */ - public static CacheProvider getConfigTimeCacheProvider() { - return configTimeCacheProviderHolder.get(); - } - - /** - * Return the LobHandler for the currently configured Hibernate SessionFactory, - * to be used by UserType implementations like ClobStringType. - *

This instance will be set before initialization of the corresponding - * SessionFactory, and reset immediately afterwards. It is thus only available - * during configuration. - * @see #setLobHandler - * @see org.springframework.orm.hibernate3.support.ClobStringType - * @see org.springframework.orm.hibernate3.support.BlobByteArrayType - * @see org.springframework.orm.hibernate3.support.BlobSerializableType - */ - public static LobHandler getConfigTimeLobHandler() { - return configTimeLobHandlerHolder.get(); - } - - - private Class configurationClass = Configuration.class; - - private Resource[] configLocations; - - private String[] mappingResources; - - private Resource[] mappingLocations; - - private Resource[] cacheableMappingLocations; - - private Resource[] mappingJarLocations; - - private Resource[] mappingDirectoryLocations; - - private Properties hibernateProperties; - - private TransactionManager jtaTransactionManager; - - private Object cacheRegionFactory; - - private CacheProvider cacheProvider; - - private LobHandler lobHandler; - - private Interceptor entityInterceptor; - - private NamingStrategy namingStrategy; - - private TypeDefinitionBean[] typeDefinitions; - - private FilterDefinition[] filterDefinitions; - - private Properties entityCacheStrategies; - - private Properties collectionCacheStrategies; - - private Map eventListeners; - - private boolean schemaUpdate = false; - - private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); - - private Configuration configuration; - - - /** - * Specify the Hibernate Configuration class to use. - * Default is "org.hibernate.cfg.Configuration"; any subclass of - * this default Hibernate Configuration class can be specified. - *

Can be set to "org.hibernate.cfg.AnnotationConfiguration" for - * using Hibernate3 annotation support (initially only available as - * alpha download separate from the main Hibernate3 distribution). - *

Annotated packages and annotated classes can be specified via the - * corresponding tags in "hibernate.cfg.xml" then, so this will usually - * be combined with a "configLocation" property that points at such a - * standard Hibernate configuration file. - * @see #setConfigLocation - * @see org.hibernate.cfg.Configuration - * @see org.hibernate.cfg.AnnotationConfiguration - */ - @SuppressWarnings("unchecked") - public void setConfigurationClass(Class configurationClass) { - if (configurationClass == null || !Configuration.class.isAssignableFrom(configurationClass)) { - throw new IllegalArgumentException( - "'configurationClass' must be assignable to [org.hibernate.cfg.Configuration]"); - } - this.configurationClass = (Class) configurationClass; - } - - /** - * Set the location of a single Hibernate XML config file, for example as - * classpath resource "classpath:hibernate.cfg.xml". - *

Note: Can be omitted when all necessary properties and mapping - * resources are specified locally via this bean. - * @see org.hibernate.cfg.Configuration#configure(java.net.URL) - */ - public void setConfigLocation(Resource configLocation) { - this.configLocations = new Resource[] {configLocation}; - } - - /** - * Set the locations of multiple Hibernate XML config files, for example as - * classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml". - *

Note: Can be omitted when all necessary properties and mapping - * resources are specified locally via this bean. - * @see org.hibernate.cfg.Configuration#configure(java.net.URL) - */ - public void setConfigLocations(Resource[] configLocations) { - this.configLocations = configLocations; - } - - /** - * Set Hibernate mapping resources to be found in the class path, - * like "example.hbm.xml" or "mypackage/example.hbm.xml". - * Analogous to mapping entries in a Hibernate XML config file. - * Alternative to the more generic setMappingLocations method. - *

Can be used to add to mappings from a Hibernate XML config file, - * or to specify all mappings locally. - * @see #setMappingLocations - * @see org.hibernate.cfg.Configuration#addResource - */ - public void setMappingResources(String[] mappingResources) { - this.mappingResources = mappingResources; - } - - /** - * Set locations of Hibernate mapping files, for example as classpath - * resource "classpath:example.hbm.xml". Supports any resource location - * via Spring's resource abstraction, for example relative paths like - * "WEB-INF/mappings/example.hbm.xml" when running in an application context. - *

Can be used to add to mappings from a Hibernate XML config file, - * or to specify all mappings locally. - * @see org.hibernate.cfg.Configuration#addInputStream - */ - public void setMappingLocations(Resource[] mappingLocations) { - this.mappingLocations = mappingLocations; - } - - /** - * Set locations of cacheable Hibernate mapping files, for example as web app - * resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location - * via Spring's resource abstraction, as long as the resource can be resolved - * in the file system. - *

Can be used to add to mappings from a Hibernate XML config file, - * or to specify all mappings locally. - * @see org.hibernate.cfg.Configuration#addCacheableFile(java.io.File) - */ - public void setCacheableMappingLocations(Resource[] cacheableMappingLocations) { - this.cacheableMappingLocations = cacheableMappingLocations; - } - - /** - * Set locations of jar files that contain Hibernate mapping resources, - * like "WEB-INF/lib/example.hbm.jar". - *

Can be used to add to mappings from a Hibernate XML config file, - * or to specify all mappings locally. - * @see org.hibernate.cfg.Configuration#addJar(java.io.File) - */ - public void setMappingJarLocations(Resource[] mappingJarLocations) { - this.mappingJarLocations = mappingJarLocations; - } - - /** - * Set locations of directories that contain Hibernate mapping resources, - * like "WEB-INF/mappings". - *

Can be used to add to mappings from a Hibernate XML config file, - * or to specify all mappings locally. - * @see org.hibernate.cfg.Configuration#addDirectory(java.io.File) - */ - public void setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) { - this.mappingDirectoryLocations = mappingDirectoryLocations; - } - - /** - * Set Hibernate properties, such as "hibernate.dialect". - *

Can be used to override values in a Hibernate XML config file, - * or to specify all necessary properties locally. - *

Note: Do not specify a transaction provider here when using - * Spring-driven transactions. It is also advisable to omit connection - * provider settings and use a Spring-set DataSource instead. - * @see #setDataSource - */ - public void setHibernateProperties(Properties hibernateProperties) { - this.hibernateProperties = hibernateProperties; - } - - /** - * Return the Hibernate properties, if any. Mainly available for - * configuration through property paths that specify individual keys. - */ - public Properties getHibernateProperties() { - if (this.hibernateProperties == null) { - this.hibernateProperties = new Properties(); - } - return this.hibernateProperties; - } - - /** - * Set the JTA TransactionManager to be used for Hibernate's - * TransactionManagerLookup. Allows for using a Spring-managed - * JTA TransactionManager for Hibernate's cache synchronization. - *

Note: If this is set, the Hibernate settings should not define a - * transaction manager lookup to avoid meaningless double configuration. - * @see LocalTransactionManagerLookup - */ - public void setJtaTransactionManager(TransactionManager jtaTransactionManager) { - this.jtaTransactionManager = jtaTransactionManager; - } +public class LocalSessionFactoryBean extends SessionFactoryBuilder implements SessionFactoryBeanOperations { - /** - * Set the Hibernate RegionFactory to use for the SessionFactory. - * Allows for using a Spring-managed RegionFactory instance. - *

As of Hibernate 3.3, this is the preferred mechanism for configuring - * caches, superseding the {@link #setCacheProvider CacheProvider SPI}. - * For Hibernate 3.2 compatibility purposes, the accepted reference is of type - * Object: the actual type is org.hibernate.cache.RegionFactory. - *

Note: If this is set, the Hibernate settings should not define a - * cache provider to avoid meaningless double configuration. - * @see org.hibernate.cache.RegionFactory - */ - public void setCacheRegionFactory(Object cacheRegionFactory) { - this.cacheRegionFactory = cacheRegionFactory; - } + private final SessionFactoryBeanDelegate delegate = new SessionFactoryBeanDelegate(this); - /** - * Set the Hibernate CacheProvider to use for the SessionFactory. - * Allows for using a Spring-managed CacheProvider instance. - *

Note: If this is set, the Hibernate settings should not define a - * cache provider to avoid meaningless double configuration. - * @deprecated as of Spring 3.0, following Hibernate 3.3's deprecation - * of the CacheProvider SPI - * @see #setCacheRegionFactory - */ @Deprecated - public void setCacheProvider(CacheProvider cacheProvider) { - this.cacheProvider = cacheProvider; - } - - /** - * Set the LobHandler to be used by the SessionFactory. - * Will be exposed at config time for UserType implementations. - * @see #getConfigTimeLobHandler - * @see org.hibernate.usertype.UserType - * @see org.springframework.orm.hibernate3.support.ClobStringType - * @see org.springframework.orm.hibernate3.support.BlobByteArrayType - * @see org.springframework.orm.hibernate3.support.BlobSerializableType - */ - public void setLobHandler(LobHandler lobHandler) { - this.lobHandler = lobHandler; - } - - /** - * Set a Hibernate entity interceptor that allows to inspect and change - * property values before writing to and reading from the database. - * Will get applied to any new Session created by this factory. - *

Such an interceptor can either be set at the SessionFactory level, i.e. on - * LocalSessionFactoryBean, or at the Session level, i.e. on HibernateTemplate, - * HibernateInterceptor, and HibernateTransactionManager. It's preferable to set - * it on LocalSessionFactoryBean or HibernateTransactionManager to avoid repeated - * configuration and guarantee consistent behavior in transactions. - * @see HibernateTemplate#setEntityInterceptor - * @see HibernateInterceptor#setEntityInterceptor - * @see HibernateTransactionManager#setEntityInterceptor - * @see org.hibernate.cfg.Configuration#setInterceptor - */ - public void setEntityInterceptor(Interceptor entityInterceptor) { - this.entityInterceptor = entityInterceptor; - } - - /** - * Set a Hibernate NamingStrategy for the SessionFactory, determining the - * physical column and table names given the info in the mapping document. - * @see org.hibernate.cfg.Configuration#setNamingStrategy - */ - public void setNamingStrategy(NamingStrategy namingStrategy) { - this.namingStrategy = namingStrategy; - } - - /** - * Specify the Hibernate type definitions to register with the SessionFactory, - * as Spring TypeDefinitionBean instances. This is an alternative to specifying - * <<typedef> elements in Hibernate mapping files. - *

Unfortunately, Hibernate itself does not define a complete object that - * represents a type definition, hence the need for Spring's TypeDefinitionBean. - * @see TypeDefinitionBean - * @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties) - */ - public void setTypeDefinitions(TypeDefinitionBean[] typeDefinitions) { - this.typeDefinitions = typeDefinitions; - } - - /** - * Specify the Hibernate FilterDefinitions to register with the SessionFactory. - * This is an alternative to specifying <<filter-def> elements in - * Hibernate mapping files. - *

Typically, the passed-in FilterDefinition objects will have been defined - * as Spring FilterDefinitionFactoryBeans, probably as inner beans within the - * LocalSessionFactoryBean definition. - * @see FilterDefinitionFactoryBean - * @see org.hibernate.cfg.Configuration#addFilterDefinition - */ - public void setFilterDefinitions(FilterDefinition[] filterDefinitions) { - this.filterDefinitions = filterDefinitions; + public void setCacheProvider(org.hibernate.cache.CacheProvider cacheProvider) { + delegate.setCacheProvider(cacheProvider); } - /** - * Specify the cache strategies for entities (persistent classes or named entities). - * This configuration setting corresponds to the <class-cache> entry - * in the "hibernate.cfg.xml" configuration format. - *

For example: - *

-	 * <property name="entityCacheStrategies">
-	 *   <props>
-	 *     <prop key="com.mycompany.Customer">read-write</prop>
-	 *     <prop key="com.mycompany.Product">read-only,myRegion</prop>
-	 *   </props>
-	 * </property>
- * @param entityCacheStrategies properties that define entity cache strategies, - * with class names as keys and cache concurrency strategies as values - * @see org.hibernate.cfg.Configuration#setCacheConcurrencyStrategy(String, String) - */ - public void setEntityCacheStrategies(Properties entityCacheStrategies) { - this.entityCacheStrategies = entityCacheStrategies; - } - - /** - * Specify the cache strategies for persistent collections (with specific roles). - * This configuration setting corresponds to the <collection-cache> entry - * in the "hibernate.cfg.xml" configuration format. - *

For example: - *

-	 * <property name="collectionCacheStrategies">
-	 *   <props>
-	 *     <prop key="com.mycompany.Order.items">read-write</prop>
-	 *     <prop key="com.mycompany.Product.categories">read-only,myRegion</prop>
-	 *   </props>
-	 * </property>
- * @param collectionCacheStrategies properties that define collection cache strategies, - * with collection roles as keys and cache concurrency strategies as values - * @see org.hibernate.cfg.Configuration#setCollectionCacheConcurrencyStrategy(String, String) - */ - public void setCollectionCacheStrategies(Properties collectionCacheStrategies) { - this.collectionCacheStrategies = collectionCacheStrategies; - } - - /** - * Specify the Hibernate event listeners to register, with listener types - * as keys and listener objects as values. Instead of a single listener object, - * you can also pass in a list or set of listeners objects as value. - *

See the Hibernate documentation for further details on listener types - * and associated listener interfaces. - * @param eventListeners Map with listener type Strings as keys and - * listener objects as values - * @see org.hibernate.cfg.Configuration#setListener(String, Object) - */ - public void setEventListeners(Map eventListeners) { - this.eventListeners = eventListeners; - } - - /** - * Set whether to execute a schema update after SessionFactory initialization. - *

For details on how to make schema update scripts work, see the Hibernate - * documentation, as this class leverages the same schema update script support - * in org.hibernate.cfg.Configuration as Hibernate's own SchemaUpdate tool. - * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript - * @see org.hibernate.tool.hbm2ddl.SchemaUpdate - */ - public void setSchemaUpdate(boolean schemaUpdate) { - this.schemaUpdate = schemaUpdate; - } - - public void setBeanClassLoader(ClassLoader beanClassLoader) { - this.beanClassLoader = beanClassLoader; - } - - @Override - @SuppressWarnings("unchecked") - protected SessionFactory buildSessionFactory() throws Exception { - // Create Configuration instance. - Configuration config = newConfiguration(); - - DataSource dataSource = getDataSource(); - if (dataSource != null) { - // Make given DataSource available for SessionFactory configuration. - configTimeDataSourceHolder.set(dataSource); - } - if (this.jtaTransactionManager != null) { - // Make Spring-provided JTA TransactionManager available. - configTimeTransactionManagerHolder.set(this.jtaTransactionManager); - } - if (this.cacheRegionFactory != null) { - // Make Spring-provided Hibernate RegionFactory available. - configTimeRegionFactoryHolder.set(this.cacheRegionFactory); - } - if (this.cacheProvider != null) { - // Make Spring-provided Hibernate CacheProvider available. - configTimeCacheProviderHolder.set(this.cacheProvider); - } - if (this.lobHandler != null) { - // Make given LobHandler available for SessionFactory configuration. - // Do early because because mapping resource might refer to custom types. - configTimeLobHandlerHolder.set(this.lobHandler); - } - - // Analogous to Hibernate EntityManager's Ejb3Configuration: - // Hibernate doesn't allow setting the bean ClassLoader explicitly, - // so we need to expose it as thread context ClassLoader accordingly. - Thread currentThread = Thread.currentThread(); - ClassLoader threadContextClassLoader = currentThread.getContextClassLoader(); - boolean overrideClassLoader = - (this.beanClassLoader != null && !this.beanClassLoader.equals(threadContextClassLoader)); - if (overrideClassLoader) { - currentThread.setContextClassLoader(this.beanClassLoader); - } - - try { - if (isExposeTransactionAwareSessionFactory()) { - // Set Hibernate 3.1+ CurrentSessionContext implementation, - // providing the Spring-managed Session as current Session. - // Can be overridden by a custom value for the corresponding Hibernate property. - config.setProperty( - Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName()); - } - - if (this.jtaTransactionManager != null) { - // Set Spring-provided JTA TransactionManager as Hibernate property. - config.setProperty( - Environment.TRANSACTION_STRATEGY, JTATransactionFactory.class.getName()); - config.setProperty( - Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName()); - } - else { - // Makes the Hibernate Session aware of the presence of a Spring-managed transaction. - // Also sets connection release mode to ON_CLOSE by default. - config.setProperty( - Environment.TRANSACTION_STRATEGY, SpringTransactionFactory.class.getName()); - } - - if (this.entityInterceptor != null) { - // Set given entity interceptor at SessionFactory level. - config.setInterceptor(this.entityInterceptor); - } - - if (this.namingStrategy != null) { - // Pass given naming strategy to Hibernate Configuration. - config.setNamingStrategy(this.namingStrategy); - } - - if (this.typeDefinitions != null) { - // Register specified Hibernate type definitions. - // Use reflection for compatibility with both Hibernate 3.3 and 3.5: - // the returned Mappings object changed from a class to an interface. - Method createMappings = Configuration.class.getMethod("createMappings"); - Method addTypeDef = createMappings.getReturnType().getMethod( - "addTypeDef", String.class, String.class, Properties.class); - Object mappings = ReflectionUtils.invokeMethod(createMappings, config); - for (TypeDefinitionBean typeDef : this.typeDefinitions) { - ReflectionUtils.invokeMethod(addTypeDef, mappings, - typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters()); - } - } - - if (this.filterDefinitions != null) { - // Register specified Hibernate FilterDefinitions. - for (FilterDefinition filterDef : this.filterDefinitions) { - config.addFilterDefinition(filterDef); - } - } - - if (this.configLocations != null) { - for (Resource resource : this.configLocations) { - // Load Hibernate configuration from given location. - config.configure(resource.getURL()); - } - } - - if (this.hibernateProperties != null) { - // Add given Hibernate properties to Configuration. - config.addProperties(this.hibernateProperties); - } - - if (dataSource != null) { - Class providerClass = LocalDataSourceConnectionProvider.class; - if (isUseTransactionAwareDataSource() || dataSource instanceof TransactionAwareDataSourceProxy) { - providerClass = TransactionAwareDataSourceConnectionProvider.class; - } - else if (config.getProperty(Environment.TRANSACTION_MANAGER_STRATEGY) != null) { - providerClass = LocalJtaDataSourceConnectionProvider.class; - } - // Set Spring-provided DataSource as Hibernate ConnectionProvider. - config.setProperty(Environment.CONNECTION_PROVIDER, providerClass.getName()); - } - - if (this.cacheRegionFactory != null) { - // Expose Spring-provided Hibernate RegionFactory. - config.setProperty(Environment.CACHE_REGION_FACTORY, - "org.springframework.orm.hibernate3.LocalRegionFactoryProxy"); - } - else if (this.cacheProvider != null) { - // Expose Spring-provided Hibernate CacheProvider. - config.setProperty(Environment.CACHE_PROVIDER, LocalCacheProviderProxy.class.getName()); - } - - if (this.mappingResources != null) { - // Register given Hibernate mapping definitions, contained in resource files. - for (String mapping : this.mappingResources) { - Resource resource = new ClassPathResource(mapping.trim(), this.beanClassLoader); - config.addInputStream(resource.getInputStream()); - } - } - - if (this.mappingLocations != null) { - // Register given Hibernate mapping definitions, contained in resource files. - for (Resource resource : this.mappingLocations) { - config.addInputStream(resource.getInputStream()); - } - } - - if (this.cacheableMappingLocations != null) { - // Register given cacheable Hibernate mapping definitions, read from the file system. - for (Resource resource : this.cacheableMappingLocations) { - config.addCacheableFile(resource.getFile()); - } - } - - if (this.mappingJarLocations != null) { - // Register given Hibernate mapping definitions, contained in jar files. - for (Resource resource : this.mappingJarLocations) { - config.addJar(resource.getFile()); - } - } - - if (this.mappingDirectoryLocations != null) { - // Register all Hibernate mapping definitions in the given directories. - for (Resource resource : this.mappingDirectoryLocations) { - File file = resource.getFile(); - if (!file.isDirectory()) { - throw new IllegalArgumentException( - "Mapping directory location [" + resource + "] does not denote a directory"); - } - config.addDirectory(file); - } - } - - // Tell Hibernate to eagerly compile the mappings that we registered, - // for availability of the mapping information in further processing. - postProcessMappings(config); - config.buildMappings(); - - if (this.entityCacheStrategies != null) { - // Register cache strategies for mapped entities. - for (Enumeration classNames = this.entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) { - String className = (String) classNames.nextElement(); - String[] strategyAndRegion = - StringUtils.commaDelimitedListToStringArray(this.entityCacheStrategies.getProperty(className)); - if (strategyAndRegion.length > 1) { - // method signature declares return type as Configuration on Hibernate 3.6 - // but as void on Hibernate 3.3 and 3.5 - Method setCacheConcurrencyStrategy = Configuration.class.getMethod( - "setCacheConcurrencyStrategy", String.class, String.class, String.class); - ReflectionUtils.invokeMethod(setCacheConcurrencyStrategy, config, - className, strategyAndRegion[0], strategyAndRegion[1]); - } - else if (strategyAndRegion.length > 0) { - config.setCacheConcurrencyStrategy(className, strategyAndRegion[0]); - } - } - } - - if (this.collectionCacheStrategies != null) { - // Register cache strategies for mapped collections. - for (Enumeration collRoles = this.collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) { - String collRole = (String) collRoles.nextElement(); - String[] strategyAndRegion = - StringUtils.commaDelimitedListToStringArray(this.collectionCacheStrategies.getProperty(collRole)); - if (strategyAndRegion.length > 1) { - config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0], strategyAndRegion[1]); - } - else if (strategyAndRegion.length > 0) { - config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0]); - } - } - } - - if (this.eventListeners != null) { - // Register specified Hibernate event listeners. - for (Map.Entry entry : this.eventListeners.entrySet()) { - String listenerType = entry.getKey(); - Object listenerObject = entry.getValue(); - if (listenerObject instanceof Collection) { - Collection listeners = (Collection) listenerObject; - EventListeners listenerRegistry = config.getEventListeners(); - Object[] listenerArray = - (Object[]) Array.newInstance(listenerRegistry.getListenerClassFor(listenerType), listeners.size()); - listenerArray = listeners.toArray(listenerArray); - config.setListeners(listenerType, listenerArray); - } - else { - config.setListener(listenerType, listenerObject); - } - } - } - - // Perform custom post-processing in subclasses. - postProcessConfiguration(config); - - // Build SessionFactory instance. - logger.info("Building new Hibernate SessionFactory"); - this.configuration = config; - return newSessionFactory(config); - } - - finally { - if (dataSource != null) { - configTimeDataSourceHolder.remove(); - } - if (this.jtaTransactionManager != null) { - configTimeTransactionManagerHolder.remove(); - } - if (this.cacheRegionFactory != null) { - configTimeCacheProviderHolder.remove(); - } - if (this.cacheProvider != null) { - configTimeCacheProviderHolder.remove(); - } - if (this.lobHandler != null) { - configTimeLobHandlerHolder.remove(); - } - if (overrideClassLoader) { - // Reset original thread context ClassLoader. - currentThread.setContextClassLoader(threadContextClassLoader); - } - } + protected final void preBuildSessionFactory() { + delegate.preBuildSessionFactory(); } - /** - * Subclasses can override this method to perform custom initialization - * of the Configuration instance used for SessionFactory creation. - * The properties of this LocalSessionFactoryBean will be applied to - * the Configuration object that gets returned here. - *

The default implementation creates a new Configuration instance. - * A custom implementation could prepare the instance in a specific way, - * or use a custom Configuration subclass. - * @return the Configuration instance - * @throws HibernateException in case of Hibernate initialization errors - * @see org.hibernate.cfg.Configuration#Configuration() - */ - protected Configuration newConfiguration() throws HibernateException { - return BeanUtils.instantiateClass(this.configurationClass); + @Override + protected final void postBuildSessionFactory() { + delegate.postBuildSessionFactory(); } - /** - * To be implemented by subclasses that want to to register further mappings - * on the Configuration object after this FactoryBean registered its specified - * mappings. - *

Invoked before the Configuration.buildMappings() call, - * so that it can still extend and modify the mapping information. - * @param config the current Configuration object - * @throws HibernateException in case of Hibernate initialization errors - * @see org.hibernate.cfg.Configuration#buildMappings() - */ - protected void postProcessMappings(Configuration config) throws HibernateException { + public void destroy() throws HibernateException { + delegate.destroy(); } - /** - * To be implemented by subclasses that want to to perform custom - * post-processing of the Configuration object after this FactoryBean - * performed its default initialization. - *

Invoked after the Configuration.buildMappings() call, - * so that it can operate on the completed and fully parsed mapping information. - * @param config the current Configuration object - * @throws HibernateException in case of Hibernate initialization errors - * @see org.hibernate.cfg.Configuration#buildMappings() - */ - protected void postProcessConfiguration(Configuration config) throws HibernateException { + public SessionFactory getObject() throws Exception { + return delegate.getSessionFactory(); } - /** - * Subclasses can override this method to perform custom initialization - * of the SessionFactory instance, creating it via the given Configuration - * object that got prepared by this LocalSessionFactoryBean. - *

The default implementation invokes Configuration's buildSessionFactory. - * A custom implementation could prepare the instance in a specific way, - * or use a custom SessionFactoryImpl subclass. - * @param config Configuration prepared by this LocalSessionFactoryBean - * @return the SessionFactory instance - * @throws HibernateException in case of Hibernate initialization errors - * @see org.hibernate.cfg.Configuration#buildSessionFactory - */ - protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { - return config.buildSessionFactory(); + public Class getObjectType() { + return delegate.getObjectType(); } - /** - * Return the Configuration object used to build the SessionFactory. - * Allows access to configuration metadata stored there (rarely needed). - * @throws IllegalStateException if the Configuration object has not been initialized yet - */ - public final Configuration getConfiguration() { - if (this.configuration == null) { - throw new IllegalStateException("Configuration not initialized yet"); - } - return this.configuration; + public void setBeanClassLoader(ClassLoader classLoader) { + delegate.setBeanClassLoader(classLoader); } - /** - * Executes schema update if requested. - * @see #setSchemaUpdate - * @see #updateDatabaseSchema() - */ - @Override - protected void afterSessionFactoryCreation() throws Exception { - if (this.schemaUpdate) { - updateDatabaseSchema(); - } + public boolean isSingleton() { + return delegate.isSingleton(); } - /** - * Allows for schema export on shutdown. - */ - @Override - public void destroy() throws HibernateException { - DataSource dataSource = getDataSource(); - if (dataSource != null) { - // Make given DataSource available for potential SchemaExport, - // which unfortunately reinstantiates a ConnectionProvider. - configTimeDataSourceHolder.set(dataSource); - } - try { - super.destroy(); - } - finally { - if (dataSource != null) { - // Reset DataSource holder. - configTimeDataSourceHolder.remove(); - } - } + public void afterPropertiesSet() throws Exception { + delegate.afterPropertiesSet(); } - - /** - * Execute schema update script, determined by the Configuration object - * used for creating the SessionFactory. A replacement for Hibernate's - * SchemaUpdate class, for automatically executing schema update scripts - * on application startup. Can also be invoked manually. - *

Fetch the LocalSessionFactoryBean itself rather than the exposed - * SessionFactory to be able to invoke this method, e.g. via - * LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");. - *

Uses the SessionFactory that this bean generates for accessing a - * JDBC connection to perform the script. - * @throws DataAccessException in case of script execution errors - * @see #setSchemaUpdate - * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript - * @see org.hibernate.tool.hbm2ddl.SchemaUpdate - */ - public void updateDatabaseSchema() throws DataAccessException { - logger.info("Updating database schema for Hibernate SessionFactory"); - DataSource dataSource = getDataSource(); - if (dataSource != null) { - // Make given DataSource available for the schema update. - configTimeDataSourceHolder.set(dataSource); - } - try { - HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory()); - hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER); - hibernateTemplate.execute( - new HibernateCallback() { - public Object doInHibernate(Session session) throws HibernateException, SQLException { - Connection con = session.connection(); - Dialect dialect = Dialect.getDialect(getConfiguration().getProperties()); - DatabaseMetadata metadata = new DatabaseMetadata(con, dialect); - String[] sql = getConfiguration().generateSchemaUpdateScript(dialect, metadata); - executeSchemaScript(con, sql); - return null; - } - } - ); - } - finally { - if (dataSource != null) { - configTimeDataSourceHolder.remove(); - } - } + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + return delegate.translateExceptionIfPossible(ex); } - /** - * Execute schema creation script, determined by the Configuration object - * used for creating the SessionFactory. A replacement for Hibernate's - * SchemaValidator class, to be invoked after application startup. - *

Fetch the LocalSessionFactoryBean itself rather than the exposed - * SessionFactory to be able to invoke this method, e.g. via - * LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");. - *

Uses the SessionFactory that this bean generates for accessing a - * JDBC connection to perform the script. - * @throws DataAccessException in case of script execution errors - * @see org.hibernate.cfg.Configuration#validateSchema - * @see org.hibernate.tool.hbm2ddl.SchemaValidator - */ - public void validateDatabaseSchema() throws DataAccessException { - logger.info("Validating database schema for Hibernate SessionFactory"); - DataSource dataSource = getDataSource(); - if (dataSource != null) { - // Make given DataSource available for the schema update. - configTimeDataSourceHolder.set(dataSource); - } - try { - HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory()); - hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER); - hibernateTemplate.execute( - new HibernateCallback() { - public Object doInHibernate(Session session) throws HibernateException, SQLException { - Connection con = session.connection(); - Dialect dialect = Dialect.getDialect(getConfiguration().getProperties()); - DatabaseMetadata metadata = new DatabaseMetadata(con, dialect, false); - getConfiguration().validateSchema(dialect, metadata); - return null; - } - } - ); - } - finally { - if (dataSource != null) { - configTimeDataSourceHolder.remove(); - } - } + public void setJdbcExceptionTranslator( + SQLExceptionTranslator jdbcExceptionTranslator) { + delegate.setJdbcExceptionTranslator(jdbcExceptionTranslator); } - /** - * Execute schema drop script, determined by the Configuration object - * used for creating the SessionFactory. A replacement for Hibernate's - * SchemaExport class, to be invoked on application setup. - *

Fetch the LocalSessionFactoryBean itself rather than the exposed - * SessionFactory to be able to invoke this method, e.g. via - * LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");. - *

Uses the SessionFactory that this bean generates for accessing a - * JDBC connection to perform the script. - * @throws org.springframework.dao.DataAccessException in case of script execution errors - * @see org.hibernate.cfg.Configuration#generateDropSchemaScript - * @see org.hibernate.tool.hbm2ddl.SchemaExport#drop - */ - public void dropDatabaseSchema() throws DataAccessException { - logger.info("Dropping database schema for Hibernate SessionFactory"); - HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory()); - hibernateTemplate.execute( - new HibernateCallback() { - public Object doInHibernate(Session session) throws HibernateException, SQLException { - Connection con = session.connection(); - Dialect dialect = Dialect.getDialect(getConfiguration().getProperties()); - String[] sql = getConfiguration().generateDropSchemaScript(dialect); - executeSchemaScript(con, sql); - return null; - } - } - ); + public void setPersistenceExceptionTranslator( + HibernateExceptionTranslator hibernateExceptionTranslator) { + delegate.setPersistenceExceptionTranslator(hibernateExceptionTranslator); } /** - * Execute schema creation script, determined by the Configuration object - * used for creating the SessionFactory. A replacement for Hibernate's - * SchemaExport class, to be invoked on application setup. - *

Fetch the LocalSessionFactoryBean itself rather than the exposed - * SessionFactory to be able to invoke this method, e.g. via - * LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");. - *

Uses the SessionFactory that this bean generates for accessing a - * JDBC connection to perform the script. - * @throws DataAccessException in case of script execution errors - * @see org.hibernate.cfg.Configuration#generateSchemaCreationScript - * @see org.hibernate.tool.hbm2ddl.SchemaExport#create + * @deprecated as of Spring 3.1 in favor of {@link #newSessionFactory()} which + * can access the internal {@code Configuration} instance via {@link #getConfiguration()}. */ - public void createDatabaseSchema() throws DataAccessException { - logger.info("Creating database schema for Hibernate SessionFactory"); - DataSource dataSource = getDataSource(); - if (dataSource != null) { - // Make given DataSource available for the schema update. - configTimeDataSourceHolder.set(dataSource); - } - try { - HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory()); - hibernateTemplate.execute( - new HibernateCallback() { - public Object doInHibernate(Session session) throws HibernateException, SQLException { - Connection con = session.connection(); - Dialect dialect = Dialect.getDialect(getConfiguration().getProperties()); - String[] sql = getConfiguration().generateSchemaCreationScript(dialect); - executeSchemaScript(con, sql); - return null; - } - } - ); - } - finally { - if (dataSource != null) { - configTimeDataSourceHolder.remove(); - } - } + @Deprecated + protected SessionFactory newSessionFactory(org.hibernate.cfg.Configuration config) throws HibernateException { + return this.newSessionFactory(); } /** - * Execute the given schema script on the given JDBC Connection. - *

Note that the default implementation will log unsuccessful statements - * and continue to execute. Override the executeSchemaStatement - * method to treat failures differently. - * @param con the JDBC Connection to execute the script on - * @param sql the SQL statements to execute - * @throws SQLException if thrown by JDBC methods - * @see #executeSchemaStatement + * @deprecated as of Spring 3.1 in favor of {@link #postProcessMappings()} which + * can access the internal {@code Configuration} instance via {@link #getConfiguration()}. */ - protected void executeSchemaScript(Connection con, String[] sql) throws SQLException { - if (sql != null && sql.length > 0) { - boolean oldAutoCommit = con.getAutoCommit(); - if (!oldAutoCommit) { - con.setAutoCommit(true); - } - try { - Statement stmt = con.createStatement(); - try { - for (String sqlStmt : sql) { - executeSchemaStatement(stmt, sqlStmt); - } - } - finally { - JdbcUtils.closeStatement(stmt); - } - } - finally { - if (!oldAutoCommit) { - con.setAutoCommit(false); - } - } - } + @Deprecated + protected void postProcessMappings(org.hibernate.cfg.Configuration config) throws HibernateException { + this.postProcessMappings(); } /** - * Execute the given schema SQL on the given JDBC Statement. - *

Note that the default implementation will log unsuccessful statements - * and continue to execute. Override this method to treat failures differently. - * @param stmt the JDBC Statement to execute the SQL on - * @param sql the SQL statement to execute - * @throws SQLException if thrown by JDBC methods (and considered fatal) + * @deprecated as of Spring 3.1 in favor of {@link #postProcessConfiguration()} which + * can access the internal {@code Configuration} instance via {@link #getConfiguration()}. */ - protected void executeSchemaStatement(Statement stmt, String sql) throws SQLException { - if (logger.isDebugEnabled()) { - logger.debug("Executing schema statement: " + sql); - } - try { - stmt.executeUpdate(sql); - } - catch (SQLException ex) { - if (logger.isWarnEnabled()) { - logger.warn("Unsuccessful schema statement: " + sql, ex); - } - } + @Deprecated + protected void postProcessConfiguration(org.hibernate.cfg.Configuration config) throws HibernateException { + this.postProcessConfiguration(); } } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalTransactionManagerLookup.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalTransactionManagerLookup.java index 0990f8384fc..f02770f621e 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalTransactionManagerLookup.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalTransactionManagerLookup.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2011 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. @@ -26,11 +26,11 @@ import org.hibernate.transaction.TransactionManagerLookup; /** * Implementation of Hibernate's {@link TransactionManagerLookup} interface * that returns a Spring-managed JTA {@link TransactionManager}, determined - * by LocalSessionFactoryBean's "jtaTransactionManager" property. + * by SessionFactoryBuilder's "jtaTransactionManager" property. * *

The main advantage of this TransactionManagerLookup is that it avoids * double configuration of JTA specifics. A single TransactionManager bean can - * be used for both JtaTransactionManager and LocalSessionFactoryBean, with no + * be used for both JtaTransactionManager and SessionFactoryBuilder, with no * JTA setup in Hibernate configuration. * *

Alternatively, use Hibernate's own TransactionManagerLookup implementations: @@ -40,7 +40,7 @@ import org.hibernate.transaction.TransactionManagerLookup; * * @author Juergen Hoeller * @since 1.2 - * @see LocalSessionFactoryBean#setJtaTransactionManager + * @see SessionFactoryBuilder#setJtaTransactionManager * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager */ public class LocalTransactionManagerLookup implements TransactionManagerLookup { @@ -49,11 +49,11 @@ public class LocalTransactionManagerLookup implements TransactionManagerLookup { public LocalTransactionManagerLookup() { - TransactionManager tm = LocalSessionFactoryBean.getConfigTimeTransactionManager(); + TransactionManager tm = SessionFactoryBuilderSupport.getConfigTimeTransactionManager(); // absolutely needs thread-bound TransactionManager to initialize if (tm == null) { throw new IllegalStateException("No JTA TransactionManager found - " + - "'jtaTransactionManager' property must be set on LocalSessionFactoryBean"); + "'jtaTransactionManager' property must be set on SessionFactoryBuilder"); } this.transactionManager = tm; } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBeanDelegate.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBeanDelegate.java new file mode 100644 index 00000000000..4bf3b613237 --- /dev/null +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBeanDelegate.java @@ -0,0 +1,198 @@ +/* + * Copyright 2002-2011 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 javax.sql.DataSource; + +import org.hibernate.HibernateException; +import org.hibernate.SessionFactory; +import org.hibernate.cache.RegionFactory; +import org.hibernate.cfg.Environment; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.support.SQLExceptionTranslator; + +/** + * Encapsulates common {@link SessionFactoryBeanOperations} behavior in order + * to avoid multiple-inheritance issues with {@code SessionFactoryBeanOperations} + * implementations that need to extend {@code *SessionFactoryBuilder} types. + * + *

Maintainer's note: Unless otherwise documented, JavaDoc for all methods is + * inherited from {@link SessionFactoryBeanOperations}. + * + * @author Chris Beams + * @since 3.1 + */ +public class SessionFactoryBeanDelegate implements SessionFactoryBeanOperations { + + private SessionFactory sessionFactory; + + private HibernateExceptionTranslator hibernateExceptionTranslator = new HibernateExceptionTranslator(); + + private final SessionFactoryBuilderSupport builder; + + private final ThreadContextClassLoaderHelper threadContextClassLoader = new ThreadContextClassLoaderHelper(); + + @Deprecated + private org.hibernate.cache.CacheProvider cacheProvider; + + @Deprecated + private static final ThreadLocal configTimeCacheProviderHolder = + new ThreadLocal(); + + /** + * Create a new {@code SessionFactoryBeanDelegate} + * @param builder the {@code *SessionFactoryBuilder} that delegates to this + * instance. + */ + public SessionFactoryBeanDelegate(SessionFactoryBuilderSupport builder) { + this.builder = builder; + } + + /** + * Return the {@code SessionFactory} maintained by this delegate. + */ + public SessionFactory getSessionFactory() { + return sessionFactory; + } + + /** + * Return the CacheProvider for the currently configured Hibernate SessionFactory, + * to be used by LocalCacheProviderProxy. + *

This instance will be set before initialization of the corresponding + * SessionFactory, and reset immediately afterwards. It is thus only available + * during configuration. + * @see #setCacheProvider + * @deprecated as of Spring 3.1 in favor of Hibernate's {@link RegionFactory} SPI + */ + @Deprecated + public static org.hibernate.cache.CacheProvider getConfigTimeCacheProvider() { + return configTimeCacheProviderHolder.get(); + } + + @Deprecated + public void setCacheProvider(org.hibernate.cache.CacheProvider cacheProvider) { + this.cacheProvider = cacheProvider; + } + + public void setPersistenceExceptionTranslator(HibernateExceptionTranslator hibernateExceptionTranslator) { + this.hibernateExceptionTranslator = hibernateExceptionTranslator; + } + + public void setBeanClassLoader(ClassLoader beanClassLoader) { + builder.setClassLoader(beanClassLoader); + } + + public SessionFactory getObject() { + return this.sessionFactory; + } + + public Class getObjectType() { + return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class); + } + + public boolean isSingleton() { + return true; + } + + public void afterPropertiesSet() throws Exception { + SessionFactory rawSf = builder.doBuildSessionFactory(); + this.sessionFactory = builder.wrapSessionFactoryIfNecessary(rawSf); + builder.afterSessionFactoryCreation(); + } + + public void destroy() throws HibernateException { + builder.logger.info("Closing Hibernate SessionFactory"); + DataSource dataSource = builder.getDataSource(); + if (dataSource != null) { + // Make given DataSource available for potential SchemaExport, + // which unfortunately reinstantiates a ConnectionProvider. + SessionFactoryBuilderSupport.configTimeDataSourceHolder.set(dataSource); + } + try { + builder.beforeSessionFactoryDestruction(); + } + finally { + this.sessionFactory.close(); + if (dataSource != null) { + // Reset DataSource holder. + SessionFactoryBuilderSupport.configTimeDataSourceHolder.remove(); + } + } + } + + public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) { + this.hibernateExceptionTranslator.setJdbcExceptionTranslator(jdbcExceptionTranslator); + } + + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + return hibernateExceptionTranslator.translateExceptionIfPossible(ex); + } + + /** + * @see SessionFactoryBuilderSupport#preBuildSessionFactory() + */ + @SuppressWarnings("deprecation") + public void preBuildSessionFactory() { + if (this.cacheProvider != null) { + // Make Spring-provided Hibernate CacheProvider available. + configTimeCacheProviderHolder.set(this.cacheProvider); + } + if (builder.getCacheRegionFactory() == null && this.cacheProvider != null) { + // Expose Spring-provided Hibernate CacheProvider. + builder.getConfiguration().setProperty(Environment.CACHE_PROVIDER, LocalCacheProviderProxy.class.getName()); + } + + // Analogous to Hibernate EntityManager's Ejb3Configuration: + // Hibernate doesn't allow setting the bean ClassLoader explicitly, + // so we need to expose it as thread context ClassLoader accordingly. + threadContextClassLoader.overrideIfNecessary(); + } + + /** + * @see SessionFactoryBuilderSupport#postBuildSessionFactory + */ + public void postBuildSessionFactory() { + if (this.cacheProvider != null) { + configTimeCacheProviderHolder.remove(); + } + threadContextClassLoader.resetIfNecessary(); + } + + + private class ThreadContextClassLoaderHelper { + private Thread currentThread = Thread.currentThread(); + private boolean shouldOverride = false; + private ClassLoader originalLoader; + + void overrideIfNecessary() { + this.originalLoader = currentThread.getContextClassLoader(); + this.shouldOverride = + (builder.getBeanClassLoader() != null && !builder.getBeanClassLoader().equals(this.originalLoader)); + if (shouldOverride) { + this.currentThread.setContextClassLoader(builder.getBeanClassLoader()); + } + } + + void resetIfNecessary() { + if (this.shouldOverride) { + // Reset original thread context ClassLoader. + this.currentThread.setContextClassLoader(this.originalLoader); + } + } + } + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBeanOperations.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBeanOperations.java new file mode 100644 index 00000000000..e4c810d8aa1 --- /dev/null +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBeanOperations.java @@ -0,0 +1,128 @@ +/* + * Copyright 2002-2011 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.hibernate.HibernateException; +import org.hibernate.SessionFactory; +import org.hibernate.cache.RegionFactory; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.jdbc.support.SQLExceptionTranslator; +import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean; + +/** + * Operations common to {@link LocalSessionFactoryBean} and + * {@link AnnotationSessionFactoryBean} types but not available via + * their respective {@code *Builder} supertypes. + * + * @author Chris Beams + * @since 3.1 + * @see LocalSessionFactoryBean + * @see AnnotationSessionFactoryBean + * @see SessionFactoryBeanDelegate + */ +public interface SessionFactoryBeanOperations + extends BeanClassLoaderAware, FactoryBean, + InitializingBean, DisposableBean, PersistenceExceptionTranslator { + + /** + * Deprecated. as of Spring 3.0 in favor of {@code setCacheRegionFactory} + * following Hibernate 3.3's deprecation of the {@code CacheProvider} SPI. + *

Set the Hibernate {@code CacheProvider} to use for the {@code SessionFactory}. + * Allows for using a Spring-managed {@code CacheProvider} instance. + *

Note: If this is set, the Hibernate settings should not define a + * cache provider to avoid meaningless double configuration. + * of the {@code CacheProvider} SPI in favor of {@link RegionFactory} SPI. + */ + @Deprecated + void setCacheProvider(org.hibernate.cache.CacheProvider cacheProvider); + + /** + * Customize the {@code HibernateExceptionTranslator} to be used when translating native + * {@code HibernateException} types to Spring's {@code DataAccessException} hierarchy. + */ + void setPersistenceExceptionTranslator(HibernateExceptionTranslator hibernateExceptionTranslator); + + /** + * Exists for compatibility with {@link BeanClassLoaderAware} but + * simply delegates to + * {@link SessionFactoryBuilderSupport#setClassLoader setClassLoader}. + */ + void setBeanClassLoader(ClassLoader beanClassLoader); + + /** + * Return the singleton SessionFactory. + */ + SessionFactory getObject() throws Exception; + + /** + * Return the SessionFactory class used. + */ + Class getObjectType(); + + /** + * Return {@code true}. + */ + boolean isSingleton(); + + /** + * Build and expose the SessionFactory. + * @see SessionFactoryBuilderSupport#buildSessionFactory + * @see SessionFactoryBuilderSupport#doBuildSessionFactory + * @see SessionFactoryBuilderSupport#wrapSessionFactoryIfNecessary + * @see SessionFactoryBuilderSupport#afterSessionFactoryCreation + */ + void afterPropertiesSet() throws Exception; + + /** + * Close the SessionFactory on bean factory shutdown. + */ + void destroy() throws HibernateException; + + /** + * Set the JDBC exception translator for the SessionFactory + * on this instance's underlying {@link #setPersistenceExceptionTranslator + * HibernateExceptionTranslator}. + *

Applied to any SQLException root cause of a Hibernate JDBCException, + * overriding Hibernate's default SQLException translation (which is + * based on Hibernate's Dialect for a specific target database). + * @param jdbcExceptionTranslator the exception translator + * @see #setPersistenceExceptionTranslator(HibernateExceptionTranslator) + * @see HibernateExceptionTranslator#setJdbcExceptionTranslator + * @see java.sql.SQLException + * @see org.hibernate.JDBCException + * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator + * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator + * @see org.springframework.dao.support.PersistenceExceptionTranslator + */ + void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator); + + /** + * Implementation of the PersistenceExceptionTranslator interface, + * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor. + *

Converts the exception if it is a HibernateException; + * else returns null to indicate an unknown exception. + * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor + * @see #convertHibernateAccessException + */ + DataAccessException translateExceptionIfPossible(RuntimeException ex); + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBuilder.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBuilder.java new file mode 100644 index 00000000000..bcd7e82d56b --- /dev/null +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBuilder.java @@ -0,0 +1,101 @@ +/* + * Copyright 2002-2011 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 javax.sql.DataSource; + +import org.hibernate.cfg.Configuration; +import org.springframework.context.annotation.Bean; + +/** + * Hibernate {@link Configuration} builder suitable for use within Spring + * {@link org.springframework.context.annotation.Configuration @Configuration} + * class {@link Bean @Bean} methods. For complete details on features, see the + * JavaDoc for the {@link SessionFactoryBuilderSupport} superclass. For use in + * Spring XML configuration, see the {@link LocalSessionFactoryBean} subclass. + * + *

As noted in {@code SessionFactoryBuilderSupport} JavaDoc, this class requires + * Hibernate 3.2 or later; it additionally requires that the Java Persistence API + * and Hibernate Annotations add-ons are present. + * + *

Setter methods return the builder instance in order to facilitate + * a concise and convenient method-chaining style. For example: + *

+ * {@code @Configuration}
+ * public class DataConfig {
+ *     {@code @Bean}
+ *     public SessionFactory sessionFactory() {
+ *         return new SessionFactoryBean()
+ *             .setDataSource(dataSource())
+ *             .setMappingLocations("classpath:com/myco/*.hbm.xml"})
+ *             .buildSessionFactory();
+ *     }
+ * }
+ * 
+ * + *

Most Hibernate configuration operations can be performed directly against + * this API; however you may also access access and configure the underlying + * {@code Configuration} object by using the {@link #doWithConfiguration} method + * and providing a {@code HibernateConfigurationCallback} as follows: + *

+ * SessionFactory sessionFactory =
+ *     new SessionFactoryBuilder()
+ *         // ...
+ *         .doWithConfiguration(new HibernateConfigurationCallback<Configuration>() {
+ *             public void configure(Configuration cfg) {
+ *                 cfg.setNamingStrategy(MyNamingStrategy.class);
+ *             }
+ *          })
+ *         .buildSessionFactory();
+ * 
+ * + * @author Juergen Hoeller + * @author Chris Beams + * @since 3.1 + * @see SessionFactoryBuilderSupport + * @see LocalSessionFactoryBean + * @see org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBuilder + * @see org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean + */ +public class SessionFactoryBuilder extends SessionFactoryBuilderSupport { + + /** + * Construct a new {@code SessionFactoryBuilder} + */ + public SessionFactoryBuilder() { + super(); + } + + /** + * Construct a new {@code SessionFactoryBuilder} with the given + * Spring-managed {@code DataSource} instance. + * @see #setDataSource + */ + public SessionFactoryBuilder(DataSource dataSource) { + super(dataSource); + } + + /** + * {@inheritDoc} + *

This implementation returns {@code org.hibernate.cfg.Configuration} + */ + @Override + protected Class getDefaultConfigurationClass() { + return Configuration.class; + } + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBuilderSupport.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBuilderSupport.java new file mode 100644 index 00000000000..c7c82d394c4 --- /dev/null +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryBuilderSupport.java @@ -0,0 +1,1408 @@ +/* + * Copyright 2002-2011 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 java.io.File; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Map; +import java.util.Properties; + +import javax.sql.DataSource; +import javax.transaction.TransactionManager; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.HibernateException; +import org.hibernate.Interceptor; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.cfg.NamingStrategy; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.FilterDefinition; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.event.EventListeners; +import org.hibernate.tool.hbm2ddl.DatabaseMetadata; +import org.hibernate.transaction.JTATransactionFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; +import org.springframework.jdbc.support.JdbcUtils; +import org.springframework.jdbc.support.lob.LobHandler; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + +/** + * Abstract base class for Spring's Hibernate {@code SessionFactory} {@code + * *Builder} and {@code *FactoryBean} types. Provides functionality suitable for + * setting up a shared Hibernate {@code SessionFactory} in a Spring application + * context; the {@code SessionFactory} can then be passed to Hibernate-based + * Repositories/DAOs via dependency injection. + * + *

Configuration settings can either be read from a + * Hibernate XML file, specified by the + * {@linkplain #setConfigLocation configLocation} property, or completely via this + * class. A typical local configuration consists of one or more {@linkplain + * #setMappingResources mappingResources}, various {@linkplain + * #setHibernateProperties hibernateProperties} (not strictly necessary), and a + * {@linkplain #setDataSource dataSource} that the {@code SessionFactory} should + * use. The latter can also be specified via Hibernate properties, but {@link + * #setDataSource} supports any Spring-configured {@code DataSource}, instead of + * relying on Hibernate's own connection providers. + * + *

This {@code SessionFactory} handling strategy is appropriate for most types + * of applications, from Hibernate-only single database apps to ones that need + * distributed transactions. Either a {@link HibernateTransactionManager} or {@link + * org.springframework.transaction.jta.JtaTransactionManager JtaTransactionManager} + * can be used for transaction demarcation, with the latter only necessary for + * transactions which span multiple databases. + * + *

By default a transaction-aware {@code SessionFactory} proxy will be exposed, + * letting data access code work with the plain Hibernate {@code SessionFactory} + * and its {@code getCurrentSession()} method, while still being able to + * participate in current Spring-managed transactions: with any transaction + * management strategy, either local or JTA / EJB CMT, and any transaction + * synchronization mechanism, either Spring or JTA. Furthermore, + * {@code getCurrentSession()} will also seamlessly work with a request-scoped + * {@code Session} managed by + * {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter} or + * {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}. + * + *

Requires Hibernate 3.2 or later; tested against 3.2, 3.3, 3.5 and 3.6. + * Note that this factory will use "on_close" as default Hibernate connection + * release mode, unless in the case of a {@linkplain #setJtaTransactionManager + * jtaTransactionManager} being specified, as this is appropriate for most + * Spring-based applications (in particular when using Spring's + * {@code HibernateTransactionManager}). + * + *

Concrete {@code *Builder} subclasses are designed for use within Spring + * {@link org.springframework.context.annotation.Configuration @Configuration} + * classes, while {@code *FactoryBean} subclasses are designed for use when + * configuring the container via Spring XML. See individual subclass documentation + * for complete details. + * + *

It is common to use the subclasses mentioned above in conjunction with + * Spring's {@link HibernateExceptionTranslator} and a + * {@code PersistenceExceptionTranslationPostProcessor} in order to convert native + * {@code HibernateException} types to Spring's {@link DataAccessException} + * hierarchy. {@code *FactoryBean} automatically perform translation through a + * built-in {@code HibernateExceptionTranslator}, but {@code @Configuration} + * class {@code @Bean} methods that use {@code *Builder} subclasses should + * manually register a {@code HibernateExceptionTranslator} {@code @Bean}. + * When using either type of subclass you must manually register a + * {@code PersistenceExceptionTranslationPostProcessor} bean. + * + * @author Juergen Hoeller + * @author Chris Beams + * @since 3.1 + * @see SessionFactoryBuilder + * @see LocalSessionFactoryBean + * @see org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBuilder + * @see org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean + * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor + * @see org.springframework.orm.hibernate3.HibernateExceptionTranslator + * @see HibernateTemplate#setSessionFactory + * @see HibernateTransactionManager#setSessionFactory + * @see #setExposeTransactionAwareSessionFactory + * @see #setJtaTransactionManager + * @see org.hibernate.SessionFactory#getCurrentSession + * @see HibernateTransactionManager + */ +public abstract class SessionFactoryBuilderSupport> { + + static final ThreadLocal configTimeDataSourceHolder = + new ThreadLocal(); + + private static final ThreadLocal configTimeTransactionManagerHolder = + new ThreadLocal(); + + private static final ThreadLocal configTimeRegionFactoryHolder = + new ThreadLocal(); + + private static final ThreadLocal configTimeLobHandlerHolder = + new ThreadLocal(); + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + @SuppressWarnings("unchecked") + private final This instance = (This) this; + + private Class configurationClass = getDefaultConfigurationClass(); + + /** Lazily initialized during calls to {@link #getConfiguration()} */ + private Configuration configuration; + + private DataSource dataSource; + + private SessionFactory sessionFactory; + + private boolean schemaUpdate = false; + + private boolean exposeTransactionAwareSessionFactory = true; + + private boolean useTransactionAwareDataSource = false; + + private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + + private Resource[] mappingLocations; + + private Resource[] cacheableMappingLocations; + + private Resource[] mappingJarLocations; + + private Resource[] mappingDirectoryLocations; + + private TransactionManager jtaTransactionManager; + + private Object cacheRegionFactory; + + private LobHandler lobHandler; + + private Interceptor entityInterceptor; + + private NamingStrategy namingStrategy; + + private TypeDefinitionBean[] typeDefinitions; + + private FilterDefinition[] filterDefinitions; + + private Resource[] configLocations; + + private Properties hibernateProperties; + + private Properties entityCacheStrategies; + + private Properties collectionCacheStrategies; + + private Map eventListeners; + + private String[] mappingResources; + + /** + * Constructor for use when DataSource is not available as a Spring bean + * instance, i.e.: when DataSource configuration should be read from + * {@code hibernate.cfg.xml} + * @see SessionFactoryBuilderSupport#AbstractSessionFactoryBuilder(DataSource) + */ + public SessionFactoryBuilderSupport() { + } + + public SessionFactoryBuilderSupport(DataSource dataSource) { + this.dataSource = dataSource; + } + + /** + * Return the default Configuration type used by this instance. + * May be overridden with {@link #setConfigurationClass(Class)}. + * @see #setConfigurationClass(Class) + */ + protected abstract Class getDefaultConfigurationClass(); + + /** + * Build the underlying Hibernate SessionFactory. + * @return the raw SessionFactory (potentially to be wrapped with a + * transaction-aware proxy before it is exposed to the application) + * @throws Exception in case of initialization failure + */ + public SessionFactory buildSessionFactory() throws Exception { + this.sessionFactory = wrapSessionFactoryIfNecessary(doBuildSessionFactory()); + afterSessionFactoryCreation(); + return this.sessionFactory; + } + + /** + * Populate the underlying {@code Configuration} instance with the various + * properties of this builder. Customization may be performed through + * {@code pre*} and {@code post*} methods. + * @see #preBuildSessionFactory() + * @see #postProcessMappings() + * @see #postBuildSessionFactory() + * @see #postBuildSessionFactory() + */ + protected final SessionFactory doBuildSessionFactory() throws Exception { + initializeConfigurationIfNecessary(); + + if (this.dataSource != null) { + // Make given DataSource available for SessionFactory configuration. + configTimeDataSourceHolder.set(this.dataSource); + } + if (this.jtaTransactionManager != null) { + // Make Spring-provided JTA TransactionManager available. + configTimeTransactionManagerHolder.set(this.jtaTransactionManager); + } + if (this.cacheRegionFactory != null) { + // Make Spring-provided Hibernate RegionFactory available. + configTimeRegionFactoryHolder.set(this.cacheRegionFactory); + } + if (this.lobHandler != null) { + // Make given LobHandler available for SessionFactory configuration. + // Do early because because mapping resource might refer to custom types. + configTimeLobHandlerHolder.set(this.lobHandler); + } + + try { + if (isExposeTransactionAwareSessionFactory()) { + // Set Hibernate 3.1+ CurrentSessionContext implementation, + // providing the Spring-managed Session as current Session. + // Can be overridden by a custom value for the corresponding Hibernate property. + this.configuration.setProperty( + Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName()); + } + + if (this.jtaTransactionManager != null) { + // Set Spring-provided JTA TransactionManager as Hibernate property. + this.configuration.setProperty( + Environment.TRANSACTION_STRATEGY, JTATransactionFactory.class.getName()); + this.configuration.setProperty( + Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName()); + } + else { + // Makes the Hibernate Session aware of the presence of a Spring-managed transaction. + // Also sets connection release mode to ON_CLOSE by default. + this.configuration.setProperty( + Environment.TRANSACTION_STRATEGY, SpringTransactionFactory.class.getName()); + } + + if (this.entityInterceptor != null) { + // Set given entity interceptor at SessionFactory level. + this.configuration.setInterceptor(this.entityInterceptor); + } + + if (this.namingStrategy != null) { + // Pass given naming strategy to Hibernate Configuration. + this.configuration.setNamingStrategy(this.namingStrategy); + } + + if (this.typeDefinitions != null) { + // Register specified Hibernate type definitions. + // Use reflection for compatibility with both Hibernate 3.3 and 3.5: + // the returned Mappings object changed from a class to an interface. + Method createMappings = Configuration.class.getMethod("createMappings"); + Method addTypeDef = createMappings.getReturnType().getMethod( + "addTypeDef", String.class, String.class, Properties.class); + Object mappings = ReflectionUtils.invokeMethod(createMappings, this.configuration); + for (TypeDefinitionBean typeDef : this.typeDefinitions) { + ReflectionUtils.invokeMethod(addTypeDef, mappings, + typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters()); + } + } + + if (this.filterDefinitions != null) { + // Register specified Hibernate FilterDefinitions. + for (FilterDefinition filterDef : this.filterDefinitions) { + this.configuration.addFilterDefinition(filterDef); + } + } + + if (this.configLocations != null) { + for (Resource resource : this.configLocations) { + // Load Hibernate configuration from given location. + this.configuration.configure(resource.getURL()); + } + } + + if (this.hibernateProperties != null) { + // Add given Hibernate properties to Configuration. + this.configuration.addProperties(this.hibernateProperties); + } + + if (dataSource != null) { + Class providerClass = LocalDataSourceConnectionProvider.class; + if (isUseTransactionAwareDataSource() || dataSource instanceof TransactionAwareDataSourceProxy) { + providerClass = TransactionAwareDataSourceConnectionProvider.class; + } + else if (this.configuration.getProperty(Environment.TRANSACTION_MANAGER_STRATEGY) != null) { + providerClass = LocalJtaDataSourceConnectionProvider.class; + } + // Set Spring-provided DataSource as Hibernate ConnectionProvider. + this.configuration.setProperty(Environment.CONNECTION_PROVIDER, providerClass.getName()); + } + + if (this.cacheRegionFactory != null) { + // Expose Spring-provided Hibernate RegionFactory. + this.configuration.setProperty(Environment.CACHE_REGION_FACTORY, + "org.springframework.orm.hibernate3.LocalRegionFactoryProxy"); + } + + if (this.mappingResources != null) { + // Register given Hibernate mapping definitions, contained in resource files. + for (String mapping : this.mappingResources) { + Resource resource = new ClassPathResource(mapping.trim(), this.beanClassLoader); + this.configuration.addInputStream(resource.getInputStream()); + } + } + + if (this.mappingLocations != null) { + // Register given Hibernate mapping definitions, contained in resource files. + for (Resource resource : this.mappingLocations) { + this.configuration.addInputStream(resource.getInputStream()); + } + } + + if (this.cacheableMappingLocations != null) { + // Register given cacheable Hibernate mapping definitions, read from the file system. + for (Resource resource : this.cacheableMappingLocations) { + this.configuration.addCacheableFile(resource.getFile()); + } + } + + if (this.mappingJarLocations != null) { + // Register given Hibernate mapping definitions, contained in jar files. + for (Resource resource : this.mappingJarLocations) { + this.configuration.addJar(resource.getFile()); + } + } + + if (this.mappingDirectoryLocations != null) { + // Register all Hibernate mapping definitions in the given directories. + for (Resource resource : this.mappingDirectoryLocations) { + File file = resource.getFile(); + if (!file.isDirectory()) { + throw new IllegalArgumentException( + "Mapping directory location [" + resource + "] does not denote a directory"); + } + this.configuration.addDirectory(file); + } + } + + // Tell Hibernate to eagerly compile the mappings that we registered, + // for availability of the mapping information in further processing. + postProcessMappings(); + this.configuration.buildMappings(); + + if (this.entityCacheStrategies != null) { + // Register cache strategies for mapped entities. + for (Enumeration classNames = this.entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) { + String className = (String) classNames.nextElement(); + String[] strategyAndRegion = + StringUtils.commaDelimitedListToStringArray(this.entityCacheStrategies.getProperty(className)); + if (strategyAndRegion.length > 1) { + // method signature declares return type as Configuration on Hibernate 3.6 + // but as void on Hibernate 3.3 and 3.5 + Method setCacheConcurrencyStrategy = Configuration.class.getMethod( + "setCacheConcurrencyStrategy", String.class, String.class, String.class); + ReflectionUtils.invokeMethod(setCacheConcurrencyStrategy, this.configuration, + className, strategyAndRegion[0], strategyAndRegion[1]); + } + else if (strategyAndRegion.length > 0) { + this.configuration.setCacheConcurrencyStrategy(className, strategyAndRegion[0]); + } + } + } + + if (this.collectionCacheStrategies != null) { + // Register cache strategies for mapped collections. + for (Enumeration collRoles = this.collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) { + String collRole = (String) collRoles.nextElement(); + String[] strategyAndRegion = + StringUtils.commaDelimitedListToStringArray(this.collectionCacheStrategies.getProperty(collRole)); + if (strategyAndRegion.length > 1) { + this.configuration.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0], strategyAndRegion[1]); + } + else if (strategyAndRegion.length > 0) { + this.configuration.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0]); + } + } + } + + if (this.eventListeners != null) { + // Register specified Hibernate event listeners. + for (Map.Entry entry : this.eventListeners.entrySet()) { + String listenerType = entry.getKey(); + Object listenerObject = entry.getValue(); + if (listenerObject instanceof Collection) { + Collection listeners = (Collection) listenerObject; + EventListeners listenerRegistry = this.configuration.getEventListeners(); + Object[] listenerArray = + (Object[]) Array.newInstance(listenerRegistry.getListenerClassFor(listenerType), listeners.size()); + listenerArray = listeners.toArray(listenerArray); + this.configuration.setListeners(listenerType, listenerArray); + } + else { + this.configuration.setListener(listenerType, listenerObject); + } + } + } + + preBuildSessionFactory(); + + // Perform custom post-processing in subclasses. + postProcessConfiguration(); + + // Build SessionFactory instance. + logger.info("Building new Hibernate SessionFactory"); + + return this.sessionFactory = newSessionFactory(); + } + finally { + if (dataSource != null) { + SessionFactoryBuilderSupport.configTimeDataSourceHolder.remove(); + } + if (this.jtaTransactionManager != null) { + SessionFactoryBuilderSupport.configTimeTransactionManagerHolder.remove(); + } + if (this.cacheRegionFactory != null) { + SessionFactoryBuilderSupport.configTimeRegionFactoryHolder.remove(); + } + if (this.lobHandler != null) { + SessionFactoryBuilderSupport.configTimeLobHandlerHolder.remove(); + } + + postBuildSessionFactory(); + } + } + + /** + * Return the Hibernate {@link Configuration} object used to build the {@link SessionFactory}. + * Allows access to configuration metadata stored there (rarely needed). + *

Favor use of {@link #doWithConfiguration(HibernateConfigurationCallback)} + * in order to customize the internal {@code Configuration} object. + * @see #doWithConfiguration(HibernateConfigurationCallback) + * @throws IllegalStateException if the Configuration object has not been initialized yet + */ + protected final Configuration getConfiguration() { + initializeConfigurationIfNecessary(); + return this.configuration; + } + + private void initializeConfigurationIfNecessary() { + if (this.configuration == null) { + this.configuration = newConfiguration(); + } + } + + /** + * Subclasses can override this method to perform custom initialization + * of the Configuration instance used for SessionFactory creation. + * The properties of this Builder will be applied to + * the Configuration object that gets returned here. + *

The default implementation creates a new Configuration instance. + * A custom implementation could prepare the instance in a specific way, + * or use a custom Configuration subclass. + * @return the Configuration instance + * @throws HibernateException in case of Hibernate initialization errors + * @see org.hibernate.cfg.Configuration#Configuration() + */ + /** + * Instantiate and return an instance of the {@link Configuration} class + * type for this builder. Subclasses may override in order to customize + * instantiation logic, but clients should use {@link #doWithConfiguration} + * to directly customize the {@code Configuration} instance. + * @see #getDefaultConfigurationClass() + * @see #setConfigurationClass(Class) + * @see #getConfiguration() + * @see #doWithConfiguration(HibernateConfigurationCallback) + */ + protected Configuration newConfiguration() { + return BeanUtils.instantiateClass(this.configurationClass); + } + + /** + * Return the exposed SessionFactory. + * Will throw an exception if not initialized yet. + * @return the SessionFactory (never null) + * @throws IllegalStateException if the SessionFactory has not been initialized yet + */ + protected final SessionFactory getSessionFactory() { + if (this.sessionFactory == null) { + throw new IllegalStateException("SessionFactory not initialized yet. Have you called buildSessionFactory()?"); + } + return this.sessionFactory; + } + + /** + * Allow additional population of the underlying {@code Configuration} + * instance. Called during {@link #doBuildSessionFactory()}. + */ + protected void preBuildSessionFactory() { + } + + /** + * Allow cleaning up resources, thread locals, etc after building the + * {@code SessionFactory}. Called during the {@code finally} block of + * {@link #doBuildSessionFactory()}. + */ + protected void postBuildSessionFactory() { + } + + /** + * Wrap the given SessionFactory with a proxy, if demanded. + *

The default implementation simply returns the given SessionFactory as-is. + * Subclasses may override this to implement transaction awareness through + * a SessionFactory proxy, for example. + * @param rawSf the raw SessionFactory as built by {@link #buildSessionFactory()} + * @return the SessionFactory reference to expose + * @see #buildSessionFactory() + */ + protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) { + return rawSf; + } + + /** + * Subclasses can override this method to perform custom initialization + * of the SessionFactory instance, creating it via the given Configuration + * object that got prepared by this Builder. + *

The default implementation invokes Configuration's buildSessionFactory. + * A custom implementation could prepare the instance in a specific way, + * or use a custom SessionFactoryImpl subclass. + * @param config Configuration prepared by this Builder + * @return the SessionFactory instance + * @throws HibernateException in case of Hibernate initialization errors + * @see org.hibernate.cfg.Configuration#buildSessionFactory + */ + protected SessionFactory newSessionFactory() throws HibernateException { + return this.configuration.buildSessionFactory(); + } + + /** + * To be implemented by subclasses that want to to register further mappings + * on the Configuration object after this FactoryBean registered its specified + * mappings. + *

Invoked before the Configuration.buildMappings() call, + * so that it can still extend and modify the mapping information. + * @param config the current Configuration object + * @throws HibernateException in case of Hibernate initialization errors + * @see org.hibernate.cfg.Configuration#buildMappings() + */ + protected void postProcessMappings() throws HibernateException { + } + + /** + * To be implemented by subclasses that want to to perform custom + * post-processing of the Configuration object after this FactoryBean + * performed its default initialization. + *

Invoked after the Configuration.buildMappings() call, + * so that it can operate on the completed and fully parsed mapping information. + * @throws HibernateException in case of Hibernate initialization errors + * @see org.hibernate.cfg.Configuration#buildMappings() + */ + protected void postProcessConfiguration() throws HibernateException { + } + + /** + * Hook that allows post-processing after the SessionFactory has been + * successfully created. The SessionFactory is already available through + * getSessionFactory() at this point. + *

This implementation is empty. + * @throws Exception in case of initialization failure + * @see #getSessionFactory() + */ + /** + * Executes schema update if requested. + * @see #setSchemaUpdate + * @see #updateDatabaseSchema() + */ + protected void afterSessionFactoryCreation() throws Exception { + if (this.schemaUpdate) { + updateDatabaseSchema(); + } + } + + /** + * Hook that allows shutdown processing before the SessionFactory + * will be closed. The SessionFactory is still available through + * getSessionFactory() at this point. + *

This implementation is empty. + * @see #getSessionFactory() + */ + protected void beforeSessionFactoryDestruction() { + } + + /** + * Execute schema creation script, determined by the Configuration object + * used for creating the SessionFactory. A replacement for Hibernate's + * SchemaExport class, to be invoked on application setup. + *

Fetch the FactoryBean itself by rather than the exposed + * SessionFactory to be able to invoke this method, e.g. via + *

+	 * LocalSessionFactoryBean sfb = ctx.getBean("&mySessionFactory", LocalSessionFactoryBean.class);
+	 * 
+ * or in the case of {@code @Configuration} class usage, register the + * SessionFactoryBuilder as a {@code @Bean} and fetch it by type: + *
+	 * SessionFactoryBuilder sfb = ctx.getBean(SessionFactoryBuilder.class);
+	 * 
+ *

Uses the SessionFactory that this bean generates for accessing a + * JDBC connection to perform the script. + * @throws DataAccessException in case of script execution errors + * @see org.hibernate.cfg.Configuration#generateSchemaCreationScript + * @see org.hibernate.tool.hbm2ddl.SchemaExport#create + */ + public void createDatabaseSchema() throws DataAccessException { + logger.info("Creating database schema for Hibernate SessionFactory"); + DataSource dataSource = getDataSource(); + if (dataSource != null) { + // Make given DataSource available for the schema update. + SessionFactoryBuilderSupport.configTimeDataSourceHolder.set(dataSource); + } + try { + HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory()); + hibernateTemplate.execute( + new HibernateCallback() { + @SuppressWarnings("deprecation") + public Object doInHibernate(Session session) throws HibernateException, SQLException { + Dialect dialect = ((SessionFactoryImplementor)session.getSessionFactory()).getDialect(); + String[] sql = configuration.generateSchemaCreationScript(dialect); + executeSchemaScript(session.connection(), sql); + return null; + } + } + ); + } + finally { + if (dataSource != null) { + SessionFactoryBuilderSupport.configTimeDataSourceHolder.remove(); + } + } + } + + /** + * Execute schema update script, determined by the Configuration object + * used for creating the SessionFactory. A replacement for Hibernate's + * SchemaUpdate class, for automatically executing schema update scripts + * on application startup. Can also be invoked manually. + *

Fetch the FactoryBean itself by rather than the exposed + * SessionFactory to be able to invoke this method, e.g. via + *

+	 * LocalSessionFactoryBean sfb = ctx.getBean("&mySessionFactory", LocalSessionFactoryBean.class);
+	 * 
+ * or in the case of {@code @Configuration} class usage, register the + * SessionFactoryBuilder as a {@code @Bean} and fetch it by type: + *
+	 * SessionFactoryBuilder sfb = ctx.getBean(SessionFactoryBuilder.class);
+	 * 
+ *

Uses the SessionFactory that this bean generates for accessing a + * JDBC connection to perform the script. + * @throws DataAccessException in case of script execution errors + * @see #setSchemaUpdate + * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript + * @see org.hibernate.tool.hbm2ddl.SchemaUpdate + */ + public void updateDatabaseSchema() throws DataAccessException { + logger.info("Updating database schema for Hibernate SessionFactory"); + if (this.dataSource != null) { + // Make given DataSource available for the schema update. + configTimeDataSourceHolder.set(this.dataSource); + } + try { + HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory()); + hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER); + hibernateTemplate.execute( + new HibernateCallback() { + public Void doInHibernate(Session session) throws HibernateException, SQLException { + @SuppressWarnings("deprecation") + Connection conn = session.connection(); + Dialect dialect = ((SessionFactoryImplementor)session.getSessionFactory()).getDialect(); + DatabaseMetadata metadata = new DatabaseMetadata(conn, dialect); + String[] sql = configuration.generateSchemaUpdateScript(dialect, metadata); + executeSchemaScript(conn, sql); + return null; + } + } + ); + } + finally { + if (dataSource != null) { + configTimeDataSourceHolder.remove(); + } + } + } + + /** + * Execute schema creation script, determined by the Configuration object + * used for creating the SessionFactory. A replacement for Hibernate's + * SchemaValidator class, to be invoked after application startup. + *

Fetch the FactoryBean itself by rather than the exposed + * SessionFactory to be able to invoke this method, e.g. via + *

+	 * LocalSessionFactoryBean sfb = ctx.getBean("&mySessionFactory", LocalSessionFactoryBean.class);
+	 * 
+ * or in the case of {@code @Configuration} class usage, register the + * SessionFactoryBuilder as a {@code @Bean} and fetch it by type: + *
+	 * SessionFactoryBuilder sfb = ctx.getBean(SessionFactoryBuilder.class);
+	 * 
+ *

Uses the SessionFactory that this bean generates for accessing a + * JDBC connection to perform the script. + * @throws DataAccessException in case of script execution errors + * @see org.hibernate.cfg.Configuration#validateSchema + * @see org.hibernate.tool.hbm2ddl.SchemaValidator + */ + public void validateDatabaseSchema() throws DataAccessException { + logger.info("Validating database schema for Hibernate SessionFactory"); + DataSource dataSource = getDataSource(); + if (dataSource != null) { + // Make given DataSource available for the schema update. + SessionFactoryBuilderSupport.configTimeDataSourceHolder.set(dataSource); + } + try { + HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory()); + hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER); + hibernateTemplate.execute( + new HibernateCallback() { + @SuppressWarnings("deprecation") + public Object doInHibernate(Session session) throws HibernateException, SQLException { + Dialect dialect = ((SessionFactoryImplementor)session.getSessionFactory()).getDialect(); + DatabaseMetadata metadata = new DatabaseMetadata(session.connection(), dialect); + configuration.validateSchema(dialect, metadata); + return null; + } + } + ); + } + finally { + if (dataSource != null) { + SessionFactoryBuilderSupport.configTimeDataSourceHolder.remove(); + } + } + } + + /** + * Execute schema drop script, determined by the Configuration object + * used for creating the SessionFactory. A replacement for Hibernate's + * SchemaExport class, to be invoked on application setup. + *

Fetch the FactoryBean itself by rather than the exposed + * SessionFactory to be able to invoke this method, e.g. via + *

+	 * LocalSessionFactoryBean sfb = ctx.getBean("&mySessionFactory", LocalSessionFactoryBean.class);
+	 * 
+ * or in the case of {@code @Configuration} class usage, register the + * SessionFactoryBuilder as a {@code @Bean} and fetch it by type: + *
+	 * SessionFactoryBuilder sfb = ctx.getBean(SessionFactoryBuilder.class);
+	 * 
+ *

Uses the SessionFactory that this bean generates for accessing a + * JDBC connection to perform the script. + * @throws org.springframework.dao.DataAccessException in case of script execution errors + * @see org.hibernate.cfg.Configuration#generateDropSchemaScript + * @see org.hibernate.tool.hbm2ddl.SchemaExport#drop + */ + public void dropDatabaseSchema() throws DataAccessException { + logger.info("Dropping database schema for Hibernate SessionFactory"); + HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory()); + hibernateTemplate.execute( + new HibernateCallback() { + @SuppressWarnings("deprecation") + public Void doInHibernate(Session session) throws HibernateException, SQLException { + Dialect dialect = ((SessionFactoryImplementor)session.getSessionFactory()).getDialect(); + String[] sql = configuration.generateDropSchemaScript(dialect); + executeSchemaScript(session.connection(), sql); + return null; + } + } + ); + } + + /** + * Execute the given schema script on the given JDBC Connection. + *

Note that the default implementation will log unsuccessful statements + * and continue to execute. Override the executeSchemaStatement + * method to treat failures differently. + * @param con the JDBC Connection to execute the script on + * @param sql the SQL statements to execute + * @throws SQLException if thrown by JDBC methods + * @see #executeSchemaStatement + */ + protected void executeSchemaScript(Connection con, String[] sql) throws SQLException { + if (sql != null && sql.length > 0) { + boolean oldAutoCommit = con.getAutoCommit(); + if (!oldAutoCommit) { + con.setAutoCommit(true); + } + try { + Statement stmt = con.createStatement(); + try { + for (String sqlStmt : sql) { + executeSchemaStatement(stmt, sqlStmt); + } + } + finally { + JdbcUtils.closeStatement(stmt); + } + } + finally { + if (!oldAutoCommit) { + con.setAutoCommit(false); + } + } + } + } + + /** + * Execute the given schema SQL on the given JDBC Statement. + *

Note that the default implementation will log unsuccessful statements + * and continue to execute. Override this method to treat failures differently. + * @param stmt the JDBC Statement to execute the SQL on + * @param sql the SQL statement to execute + * @throws SQLException if thrown by JDBC methods (and considered fatal) + */ + protected void executeSchemaStatement(Statement stmt, String sql) throws SQLException { + if (logger.isDebugEnabled()) { + logger.debug("Executing schema statement: " + sql); + } + try { + stmt.executeUpdate(sql); + } + catch (SQLException ex) { + if (logger.isWarnEnabled()) { + logger.warn("Unsuccessful schema statement: " + sql, ex); + } + } + } + + /** + * Specify the Hibernate Configuration class to use. + * Default is {@code org.hibernate.cfg.Configuration}; any subclass of + * this default Hibernate {@code Configuration} class can be specified. + *

Can be set to {@code org.hibernate.cfg.AnnotationConfiguration} for + * using Hibernate3 annotation support (initially only available as + * alpha download separate from the main Hibernate3 distribution). + *

Annotated packages and annotated classes can be specified via the + * corresponding tags in "hibernate.cfg.xml" then, so this will usually + * be combined with a "configLocation" property that points at such a + * standard Hibernate configuration file. + * @see #setConfigLocation + * @see #doWithConfiguration + * @see org.hibernate.cfg.Configuration + * @see org.hibernate.cfg.AnnotationConfiguration + */ + public final This setConfigurationClass(Class configurationClass) { + Assert.notNull(configurationClass, "configurationClass must not be null"); + if (this.configuration != null) { + throw new IllegalStateException( + "setConfigurationClass() must be called before the internal " + + "Configuration instance has been created. Have you perhaps called " + + "getConfiguration() or doWithConfiguration() earlier than your call " + + "to setConfiguration()?"); + } + this.configurationClass = configurationClass; + return this.instance; + } + + /** + * Use the given {@link HibernateConfigurationCallback} instance to configure + * this {@code Builder}'s underlying Hibernate {@code Configuration} object. + *

The {@code HibernateConfigurationCallback} type may be parameterized to + * {@code org.hibernate.cfg.Configuration} (the default), or {@code + * org.hibernate.cfg.AnnotationConfiguration} if running a Hibernate version + * less than 3.6. Otherwise, may be parameterized to any custom {@code Configuration} + * class provided to {@link #setConfigurationClass} + * @throws Exception propagating any exception thrown during operations against + * the underlying {@code Configuration} object. {@code @Bean} methods should + * declare {@code throws Exception} when using this method, allowing the Spring + * container to deal with it and fail appropriately. + * @see #setConfigurationClass(Class) + */ + @SuppressWarnings("unchecked") + public This doWithConfiguration(HibernateConfigurationCallback callback) + throws Exception { + callback.configure((C)this.getConfiguration()); + return this.instance; + } + + /** + * Set the DataSource to be used by the SessionFactory. + * If set, this will override corresponding settings in Hibernate properties. + *

If this is set, the Hibernate settings should not define + * a connection provider to avoid meaningless double configuration. + *

If using HibernateTransactionManager as transaction strategy, consider + * proxying your target DataSource with a LazyConnectionDataSourceProxy. + * This defers fetching of an actual JDBC Connection until the first JDBC + * Statement gets executed, even within JDBC transactions (as performed by + * HibernateTransactionManager). Such lazy fetching is particularly beneficial + * for read-only operations, in particular if the chances of resolving the + * result in the second-level cache are high. + *

As JTA and transactional JNDI DataSources already provide lazy enlistment + * of JDBC Connections, LazyConnectionDataSourceProxy does not add value with + * JTA (i.e. Spring's JtaTransactionManager) as transaction strategy. + * @see #setUseTransactionAwareDataSource + * @see HibernateTransactionManager + * @see org.springframework.transaction.jta.JtaTransactionManager + * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy + */ + public This setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + return this.instance; + } + + /** + * Return the DataSource to be used by the SessionFactory. + */ + public DataSource getDataSource() { + return this.dataSource; + } + + + /** + * Set the location of a single Hibernate XML config file, for example as + * classpath resource "classpath:hibernate.cfg.xml". + *

Note: Can be omitted when all necessary properties and mapping + * resources are specified locally via this bean. + * @see org.hibernate.cfg.Configuration#configure(java.net.URL) + */ + public void setConfigLocation(Resource configLocation) { + this.configLocations = new Resource[] {configLocation}; + } + + /** + * Return the Hibernate properties, if any. Mainly available for + * configuration through property paths that specify individual keys. + */ + public Properties getHibernateProperties() { + if (this.hibernateProperties == null) { + this.hibernateProperties = new Properties(); + } + return this.hibernateProperties; + } + + /** + * Set locations of cacheable Hibernate mapping files, for example as web app + * resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location + * via Spring's resource abstraction, as long as the resource can be resolved + * in the file system. + *

Can be used to add to mappings from a Hibernate XML config file, + * or to specify all mappings locally. + * @see org.hibernate.cfg.Configuration#addCacheableFile(java.io.File) + */ + public void setCacheableMappingLocations(Resource[] cacheableMappingLocations) { + this.cacheableMappingLocations = cacheableMappingLocations; + } + + + /** + * Set the locations of multiple Hibernate XML config files, for example as + * classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml". + *

Note: Can be omitted when all necessary properties and mapping + * resources are specified locally via this bean. + * @see org.hibernate.cfg.Configuration#configure(java.net.URL) + */ + public void setConfigLocations(Resource[] configLocations) { + this.configLocations = configLocations; + } + + /** + * Set the LobHandler to be used by the SessionFactory. + * Will be exposed at config time for UserType implementations. + * @see #getConfigTimeLobHandler + * @see org.hibernate.usertype.UserType + * @see org.springframework.orm.hibernate3.support.ClobStringType + * @see org.springframework.orm.hibernate3.support.BlobByteArrayType + * @see org.springframework.orm.hibernate3.support.BlobSerializableType + */ + public void setLobHandler(LobHandler lobHandler) { + this.lobHandler = lobHandler; + } + + /** + * Set the Hibernate RegionFactory to use for the SessionFactory. + * Allows for using a Spring-managed RegionFactory instance. + *

As of Hibernate 3.3, this is the preferred mechanism for configuring + * caches, superseding the {@link #setCacheProvider CacheProvider SPI}. + * For Hibernate 3.2 compatibility purposes, the accepted reference is of type + * Object: the actual type is org.hibernate.cache.RegionFactory. + *

Note: If this is set, the Hibernate settings should not define a + * cache provider to avoid meaningless double configuration. + * @see org.hibernate.cache.RegionFactory + */ + public This setCacheRegionFactory(Object cacheRegionFactory) { + this.cacheRegionFactory = cacheRegionFactory; + return instance; + } + + protected Object getCacheRegionFactory() { + return this.cacheRegionFactory; + } + + /** + * Set whether to expose a transaction-aware current Session from the + * SessionFactory's getCurrentSession() method, returning the + * Session that's associated with the current Spring-managed transaction, if any. + *

Default is "true", letting data access code work with the plain + * Hibernate SessionFactory and its getCurrentSession() method, + * while still being able to participate in current Spring-managed transactions: + * with any transaction management strategy, either local or JTA / EJB CMT, + * and any transaction synchronization mechanism, either Spring or JTA. + * Furthermore, getCurrentSession() will also seamlessly work with + * a request-scoped Session managed by OpenSessionInViewFilter/Interceptor. + *

Turn this flag off to expose the plain Hibernate SessionFactory with + * Hibernate's default getCurrentSession() behavior, supporting + * plain JTA synchronization only. Alternatively, simply override the + * corresponding Hibernate property "hibernate.current_session_context_class". + * @see SpringSessionContext + * @see org.hibernate.SessionFactory#getCurrentSession() + * @see org.springframework.transaction.jta.JtaTransactionManager + * @see HibernateTransactionManager + * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter + * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor + */ + public This setExposeTransactionAwareSessionFactory(boolean exposeTransactionAwareSessionFactory) { + this.exposeTransactionAwareSessionFactory = exposeTransactionAwareSessionFactory; + return this.instance; + } + + /** + * Return whether to expose a transaction-aware proxy for the SessionFactory. + */ + protected boolean isExposeTransactionAwareSessionFactory() { + return this.exposeTransactionAwareSessionFactory; + } + + /** + * Set whether to use a transaction-aware DataSource for the SessionFactory, + * i.e. whether to automatically wrap the passed-in DataSource with Spring's + * TransactionAwareDataSourceProxy. + *

Default is "false": SessionFactoryBuilder types are usually used with Spring's + * HibernateTransactionManager or JtaTransactionManager, both of which work nicely + * on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are + * fully managed by the Hibernate/JTA transaction infrastructure in such a scenario. + *

If you switch this flag to "true", Spring's Hibernate access will be able to + * participate in JDBC-based transactions managed outside of Hibernate + * (for example, by Spring's DataSourceTransactionManager). This can be convenient + * if you need a different local transaction strategy for another O/R mapping tool, + * for example, but still want Hibernate access to join into those transactions. + *

A further benefit of this option is that plain Sessions opened directly + * via the SessionFactory, outside of Spring's Hibernate support, will still + * participate in active Spring-managed transactions. However, consider using + * Hibernate's getCurrentSession() method instead (see javadoc of + * "exposeTransactionAwareSessionFactory" property). + *

WARNING: When using a transaction-aware JDBC DataSource in combination + * with OpenSessionInViewFilter/Interceptor, whether participating in JTA or + * external JDBC-based transactions, it is strongly recommended to set Hibernate's + * Connection release mode to "after_transaction" or "after_statement", which + * guarantees proper Connection handling in such a scenario. In contrast to that, + * HibernateTransactionManager generally requires release mode "on_close". + *

Note: If you want to use Hibernate's Connection release mode "after_statement" + * with a DataSource specified on this SessionFactoryBuilder (for example, a + * JTA-aware DataSource fetched from JNDI), switch this setting to "true". + * Otherwise, the ConnectionProvider used underneath will vote against aggressive + * release and thus silently switch to release mode "after_transaction". + * @see #setDataSource + * @see #setExposeTransactionAwareSessionFactory + * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy + * @see org.springframework.jdbc.datasource.DataSourceTransactionManager + * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter + * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor + * @see HibernateTransactionManager + * @see org.springframework.transaction.jta.JtaTransactionManager + */ + public This setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) { + this.useTransactionAwareDataSource = useTransactionAwareDataSource; + return instance; + } + + /** + * Return whether to use a transaction-aware DataSource for the SessionFactory. + */ + protected boolean isUseTransactionAwareDataSource() { + return this.useTransactionAwareDataSource; + } + + /** + * Set the JTA TransactionManager to be used for Hibernate's + * TransactionManagerLookup. Allows for using a Spring-managed + * JTA TransactionManager for Hibernate's cache synchronization. + *

Note: If this is set, the Hibernate settings should not define a + * transaction manager lookup to avoid meaningless double configuration. + * @see LocalTransactionManagerLookup + */ + public This setJtaTransactionManager(TransactionManager jtaTransactionManager) { + this.jtaTransactionManager = jtaTransactionManager; + return instance; + } + + /** + * Set whether to execute a schema update after SessionFactory initialization. + *

For details on how to make schema update scripts work, see the Hibernate + * documentation, as this class leverages the same schema update script support + * in org.hibernate.cfg.Configuration as Hibernate's own SchemaUpdate tool. + * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript + * @see org.hibernate.tool.hbm2ddl.SchemaUpdate + */ + public This setSchemaUpdate(boolean schemaUpdate) { + this.schemaUpdate = schemaUpdate; + return this.instance; + } + + /** + * Set the beanClassLoader for this instance. Not named {@code setBeanClassLoader} + * to allow subclasses to implement {@code BeanClassLoaderAware} without violating + * this method's signature. Any such implementation should simply delegate to this + * method. + * @see #getBeanClassLoader() + */ + public This setClassLoader(ClassLoader beanClassLoader) { + this.beanClassLoader = beanClassLoader; + return this.instance; + } + + /** + * @see #setClassLoader(ClassLoader) + */ + protected ClassLoader getBeanClassLoader() { + return this.beanClassLoader; + } + + /** + * Set Hibernate mapping resources to be found in the class path, + * like "example.hbm.xml" or "mypackage/example.hbm.xml". + * Analogous to mapping entries in a Hibernate XML config file. + * Alternative to the more generic setMappingLocations method. + *

Can be used to add to mappings from a Hibernate XML config file, + * or to specify all mappings locally. + * @see #setMappingLocations + * @see org.hibernate.cfg.Configuration#addResource + */ + public This setMappingResources(String[] mappingResources) { + this.mappingResources = mappingResources; + return instance; + } + + /** + * Set locations of jar files that contain Hibernate mapping resources, + * like "WEB-INF/lib/example.hbm.jar". + *

Can be used to add to mappings from a Hibernate XML config file, + * or to specify all mappings locally. + * @see org.hibernate.cfg.Configuration#addJar(java.io.File) + */ + public This setMappingJarLocations(Resource[] mappingJarLocations) { + this.mappingJarLocations = mappingJarLocations; + return instance; + } + + /** + * Set locations of directories that contain Hibernate mapping resources, + * like "WEB-INF/mappings". + *

Can be used to add to mappings from a Hibernate XML config file, + * or to specify all mappings locally. + * @see org.hibernate.cfg.Configuration#addDirectory(java.io.File) + */ + public This setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) { + this.mappingDirectoryLocations = mappingDirectoryLocations; + return instance; + } + + /** + * Set locations of Hibernate mapping files, for example as classpath + * resource "classpath:example.hbm.xml". Supports any resource location + * via Spring's resource abstraction, for example relative paths like + * "WEB-INF/mappings/example.hbm.xml" when running in an application context. + *

Can be used to add to mappings from a Hibernate XML config file, + * or to specify all mappings locally. + * @see org.hibernate.cfg.Configuration#addInputStream + */ + public This setMappingLocations(Resource[] mappingLocations) { + this.mappingLocations = mappingLocations; + return instance; + } + + /** + * Set Hibernate properties, such as "hibernate.dialect". + *

Can be used to override values in a Hibernate XML config file, + * or to specify all necessary properties locally. + *

Note: Do not specify a transaction provider here when using + * Spring-driven transactions. It is also advisable to omit connection + * provider settings and use a Spring-set DataSource instead. + * @see #setDataSource + */ + public This setHibernateProperties(Properties hibernateProperties) { + this.hibernateProperties = hibernateProperties; + return instance; + } + + /** + * Set a Hibernate entity interceptor that allows to inspect and change + * property values before writing to and reading from the database. + * Will get applied to any new Session created by this factory. + *

Such an interceptor can either be set at the SessionFactory level, i.e. on + * SessionFactoryBuilder, or at the Session level, i.e. on HibernateTemplate, + * HibernateInterceptor, and HibernateTransactionManager. It's preferable to set + * it on SessionFactoryBuilder or HibernateTransactionManager to avoid repeated + * configuration and guarantee consistent behavior in transactions. + * @see HibernateTemplate#setEntityInterceptor + * @see HibernateInterceptor#setEntityInterceptor + * @see HibernateTransactionManager#setEntityInterceptor + * @see org.hibernate.cfg.Configuration#setInterceptor + */ + public This setEntityInterceptor(Interceptor entityInterceptor) { + this.entityInterceptor = entityInterceptor; + return instance; + } + + /** + * Set a Hibernate NamingStrategy for the SessionFactory, determining the + * physical column and table names given the info in the mapping document. + * @see org.hibernate.cfg.Configuration#setNamingStrategy + */ + public This setNamingStrategy(NamingStrategy namingStrategy) { + this.namingStrategy = namingStrategy; + return instance; + } + + /** + * Specify the cache strategies for entities (persistent classes or named entities). + * This configuration setting corresponds to the {@code } entry + * in the "hibernate.cfg.xml" configuration format. + *

For example: + *

+	 * {@code
+	 * 
+	 *   
+	 *     read-write
+	 *     read-only,myRegion
+	 *   
+	 * }
+ * @param entityCacheStrategies properties that define entity cache strategies, + * with class names as keys and cache concurrency strategies as values + * @see org.hibernate.cfg.Configuration#setCacheConcurrencyStrategy(String, String) + */ + public This setEntityCacheStrategies(Properties entityCacheStrategies) { + this.entityCacheStrategies = entityCacheStrategies; + return instance; + } + + /** + * Specify the cache strategies for persistent collections (with specific roles). + * This configuration setting corresponds to the {@code } entry + * in the "hibernate.cfg.xml" configuration format. + *

For example: + *

+	 * {@code
+	 * 
+	 *   
+	 *     read-write
+	 *     read-only,myRegion
+	 *   
+	 * }
+ * @param collectionCacheStrategies properties that define collection cache strategies, + * with collection roles as keys and cache concurrency strategies as values + * @see org.hibernate.cfg.Configuration#setCollectionCacheConcurrencyStrategy(String, String) + */ + public This setCollectionCacheStrategies(Properties collectionCacheStrategies) { + this.collectionCacheStrategies = collectionCacheStrategies; + return instance; + } + + /** + * Specify the Hibernate event listeners to register, with listener types + * as keys and listener objects as values. Instead of a single listener object, + * you can also pass in a list or set of listeners objects as value. + *

See the Hibernate documentation for further details on listener types + * and associated listener interfaces. + * @param eventListeners Map with listener type Strings as keys and + * listener objects as values + * @see org.hibernate.cfg.Configuration#setListener(String, Object) + */ + public This setEventListeners(Map eventListeners) { + this.eventListeners = eventListeners; + return this.instance; + } + + /** + * Specify the Hibernate FilterDefinitions to register with the SessionFactory. + * This is an alternative to specifying {@code } elements in + * Hibernate mapping files. + *

Typically, the passed-in FilterDefinition objects will have been defined + * as Spring FilterDefinitionFactoryBeans, probably as inner beans within the + * LocalSessionFactoryBean definition. + * @see FilterDefinitionFactoryBean + * @see org.hibernate.cfg.Configuration#addFilterDefinition + */ + public This setFilterDefinitions(FilterDefinition[] filterDefinitions) { + this.filterDefinitions = filterDefinitions; + return this.instance; + } + + /** + * Specify the Hibernate type definitions to register with the SessionFactory, + * as Spring TypeDefinitionBean instances. This is an alternative to specifying + * {@code } elements in Hibernate mapping files. + *

Unfortunately, Hibernate itself does not define a complete object that + * represents a type definition, hence the need for Spring's TypeDefinitionBean. + * @see TypeDefinitionBean + * @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties) + */ + public This setTypeDefinitions(TypeDefinitionBean[] typeDefinitions) { + this.typeDefinitions = typeDefinitions; + return this.instance; + } + + /** + * Return the DataSource for the currently configured Hibernate SessionFactory, + * to be used by LocalDataSourceConnectionProvoder. + *

This instance will be set before initialization of the corresponding + * SessionFactory, and reset immediately afterwards. It is thus only available + * during configuration. + * @see #setDataSource + * @see LocalDataSourceConnectionProvider + */ + public static DataSource getConfigTimeDataSource() { + return configTimeDataSourceHolder.get(); + } + + /** + * Return the JTA TransactionManager for the currently configured Hibernate + * SessionFactory, to be used by LocalTransactionManagerLookup. + *

This instance will be set before initialization of the corresponding + * SessionFactory, and reset immediately afterwards. It is thus only available + * during configuration. + * @see #setJtaTransactionManager + * @see LocalTransactionManagerLookup + */ + public static TransactionManager getConfigTimeTransactionManager() { + return configTimeTransactionManagerHolder.get(); + } + + /** + * Return the RegionFactory for the currently configured Hibernate SessionFactory, + * to be used by LocalRegionFactoryProxy. + *

This instance will be set before initialization of the corresponding + * SessionFactory, and reset immediately afterwards. It is thus only available + * during configuration. + * @see #setCacheRegionFactory + */ + static Object getConfigTimeRegionFactory() { + return configTimeRegionFactoryHolder.get(); + } + + /** + * Return the LobHandler for the currently configured Hibernate SessionFactory, + * to be used by UserType implementations like ClobStringType. + *

This instance will be set before initialization of the corresponding + * SessionFactory, and reset immediately afterwards. It is thus only available + * during configuration. + * @see #setLobHandler + * @see org.springframework.orm.hibernate3.support.ClobStringType + * @see org.springframework.orm.hibernate3.support.BlobByteArrayType + * @see org.springframework.orm.hibernate3.support.BlobSerializableType + */ + public static LobHandler getConfigTimeLobHandler() { + return configTimeLobHandlerHolder.get(); + } + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryUtils.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryUtils.java index ab6042cc206..2cacab471e1 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryUtils.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryUtils.java @@ -212,7 +212,7 @@ public abstract class SessionFactoryUtils { *

Supports setting a Session-level Hibernate entity interceptor that allows * to inspect and change property values before writing to and reading from the * database. Such an interceptor can also be set at the SessionFactory level - * (i.e. on LocalSessionFactoryBean), on HibernateTransactionManager, or on + * (i.e. on SessionFactoryBuilder), on HibernateTransactionManager, or on * HibernateInterceptor/HibernateTemplate. * @param sessionFactory Hibernate SessionFactory to create the session with * @param entityInterceptor Hibernate entity interceptor, or null if none @@ -221,7 +221,7 @@ public abstract class SessionFactoryUtils { * when actually registering a transaction synchronization) * @return the Hibernate Session * @throws DataAccessResourceFailureException if the Session couldn't be created - * @see LocalSessionFactoryBean#setEntityInterceptor + * @see SessionFactoryBuilder#setEntityInterceptor * @see HibernateInterceptor#setEntityInterceptor * @see HibernateTemplate#setEntityInterceptor */ diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SpringSessionContext.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SpringSessionContext.java index e914c19fe4b..77695e7ea43 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SpringSessionContext.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SpringSessionContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2011 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. @@ -26,7 +26,7 @@ import org.hibernate.engine.SessionFactoryImplementor; * that delegates to Spring's SessionFactoryUtils for providing a * Spring-managed current Session. * - *

Used by Spring's {@link LocalSessionFactoryBean} when told to expose a + *

Used by Spring's {@link SessionFactoryBuilder} when told to expose a * transaction-aware SessionFactory. This is the default as of Spring 2.5. * *

This CurrentSessionContext implementation can also be specified in custom @@ -36,8 +36,9 @@ import org.hibernate.engine.SessionFactoryImplementor; * @author Juergen Hoeller * @since 2.0 * @see SessionFactoryUtils#doGetSession - * @see LocalSessionFactoryBean#setExposeTransactionAwareSessionFactory + * @see SessionFactoryBuilder#setExposeTransactionAwareSessionFactory */ +@SuppressWarnings("serial") public class SpringSessionContext implements CurrentSessionContext { private final SessionFactoryImplementor sessionFactory; diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/TransactionAwareDataSourceConnectionProvider.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/TransactionAwareDataSourceConnectionProvider.java index e8233d2c1ea..a9425c1e78e 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/TransactionAwareDataSourceConnectionProvider.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/TransactionAwareDataSourceConnectionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2011 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. @@ -23,11 +23,11 @@ import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy; /** * Subclass of LocalDataSourceConnectionProvider that returns a * transaction-aware proxy for the exposed DataSource. Used if - * LocalSessionFactoryBean's "useTransactionAwareDataSource" flag is on. + * SessionFactoryBuilder's "useTransactionAwareDataSource" flag is on. * * @author Juergen Hoeller * @since 1.2 - * @see LocalSessionFactoryBean#setUseTransactionAwareDataSource + * @see SessionFactoryBuilder#setUseTransactionAwareDataSource */ public class TransactionAwareDataSourceConnectionProvider extends LocalDataSourceConnectionProvider { diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/TypeDefinitionBean.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/TypeDefinitionBean.java index 68140afdf89..406c5a70f1a 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/TypeDefinitionBean.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/TypeDefinitionBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005 the original author or authors. + * Copyright 2002-2011 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. @@ -28,19 +28,20 @@ import org.springframework.beans.factory.InitializingBean; * definition, as list element for the "typeDefinitions" bean property. * For example: * - *

- * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
+ * 
+ * {@code
+ * 
  *   ...
- *   <property name="typeDefinitions">
- *     <list>
- *       <bean class="org.springframework.orm.hibernate3.TypeDefinitionBean">
- *         <property name="typeName" value="myType"/>
- *         <property name="typeClass" value="mypackage.MyTypeClass"/>
- *       </bean>
- *     </list>
- *   </property>
+ *   
+ *     
+ *       
+ *         
+ *         
+ *       
+ *     
+ *   
  *   ...
- * </bean>
+ * }
* * Alternatively, specify a bean id (or name) attribute for the inner bean, * instead of the "typeName" property. diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.java index a4649337ace..3ecc5c9423a 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2011 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. @@ -16,233 +16,169 @@ package org.springframework.orm.hibernate3.annotation; -import java.io.IOException; -import javax.persistence.Embeddable; -import javax.persistence.Entity; -import javax.persistence.MappedSuperclass; - import org.hibernate.HibernateException; -import org.hibernate.MappingException; -import org.hibernate.cfg.AnnotationConfiguration; -import org.hibernate.cfg.Configuration; - +import org.hibernate.SessionFactory; import org.springframework.context.ResourceLoaderAware; -import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternUtils; -import org.springframework.core.type.classreading.CachingMetadataReaderFactory; -import org.springframework.core.type.classreading.MetadataReader; -import org.springframework.core.type.classreading.MetadataReaderFactory; -import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.core.type.filter.TypeFilter; -import org.springframework.orm.hibernate3.LocalSessionFactoryBean; -import org.springframework.util.ClassUtils; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.support.SQLExceptionTranslator; +import org.springframework.orm.hibernate3.HibernateExceptionTranslator; +import org.springframework.orm.hibernate3.SessionFactoryBeanOperations; +import org.springframework.orm.hibernate3.SessionFactoryBeanDelegate; +import org.springframework.orm.hibernate3.SessionFactoryBuilderSupport; /** - * Subclass of Spring's standard LocalSessionFactoryBean for Hibernate, - * supporting JDK 1.5+ annotation metadata for mappings. + * Subclass of {@link AnnotationSessionFactoryBuilder} adhering to Spring's + * {@link org.springframework.beans.factory.FactoryBean FactoryBean} contract, + * making it suitable for use in XML configuration. * - *

Note: This class requires Hibernate 3.2 or later, with the - * Java Persistence API and the Hibernate Annotations add-on present. - * - *

Example for an AnnotationSessionFactoryBean bean definition: + *

A typical {@code AnnotationSessionFactoryBean} bean definition: * *

- * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
- *   <property name="dataSource" ref="dataSource"/>
- *   <property name="annotatedClasses">
- *     <list>
- *       <value>test.package.Foo</value>
- *       <value>test.package.Bar</value>
- *     </list>
- *   </property>
- * </bean>
+ * {@code + * + * + * + * + * test.package.Foo + * test.package.Bar + * + * + * } * * Or when using classpath scanning for autodetection of entity classes: * *
- * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
- *   <property name="dataSource" ref="dataSource"/>
- *   <property name="packagesToScan" value="test.package"/>
- * </bean>
+ * {@code + * + * + * + * } + * + *

Implements the + * {@link org.springframework.dao.support.PersistenceExceptionTranslator + * PersistenceExceptionTranslator} interface, as autodetected by Spring's {@link + * org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor + * PersistenceExceptionTranslationPostProcessor}, for AOP-based translation of + * native Hibernate exceptions to Spring's {@link DataAccessException} hierarchy. + * Hence, the presence of an {@code AnnotationSessionFactoryBean} automatically + * enables a {@code PersistenceExceptionTranslationPostProcessor} to translate + * Hibernate exceptions. * * @author Juergen Hoeller + * @author Chris Beams * @since 1.2.2 - * @see #setDataSource - * @see #setHibernateProperties - * @see #setAnnotatedClasses - * @see #setAnnotatedPackages + * @see SessionFactoryBuilderSupport + * @see AnnotationSessionFactoryBuilder */ -public class AnnotationSessionFactoryBean extends LocalSessionFactoryBean implements ResourceLoaderAware { +public class AnnotationSessionFactoryBean extends AnnotationSessionFactoryBuilder + implements SessionFactoryBeanOperations, ResourceLoaderAware { - private static final String RESOURCE_PATTERN = "/**/*.class"; + private final SessionFactoryBeanDelegate delegate = new SessionFactoryBeanDelegate(this); + @Deprecated + public void setCacheProvider(org.hibernate.cache.CacheProvider cacheProvider) { + delegate.setCacheProvider(cacheProvider); + } - private Class[] annotatedClasses; - - private String[] annotatedPackages; - - private String[] packagesToScan; - - private TypeFilter[] entityTypeFilters = new TypeFilter[] { - new AnnotationTypeFilter(Entity.class, false), - new AnnotationTypeFilter(Embeddable.class, false), - new AnnotationTypeFilter(MappedSuperclass.class, false), - new AnnotationTypeFilter(org.hibernate.annotations.Entity.class, false)}; + @Override + protected void preBuildSessionFactory() { + delegate.preBuildSessionFactory(); + } - private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); + @Override + protected void postBuildSessionFactory() { + delegate.postBuildSessionFactory(); + } + public void setResourceLoader(ResourceLoader resourceLoader) { + this.setResourcePatternResolver(ResourcePatternUtils.getResourcePatternResolver(resourceLoader)); + } - public AnnotationSessionFactoryBean() { - setConfigurationClass(AnnotationConfiguration.class); + public void destroy() throws HibernateException { + delegate.destroy(); } + public SessionFactory getObject() { + return delegate.getObject(); + } - @Override - public void setConfigurationClass(Class configurationClass) { - if (configurationClass == null || !AnnotationConfiguration.class.isAssignableFrom(configurationClass)) { - throw new IllegalArgumentException( - "AnnotationSessionFactoryBean only supports AnnotationConfiguration or subclasses"); - } - super.setConfigurationClass(configurationClass); + public Class getObjectType() { + return delegate.getObjectType(); } - /** - * Specify annotated classes, for which mappings will be read from - * class-level JDK 1.5+ annotation metadata. - * @see org.hibernate.cfg.AnnotationConfiguration#addAnnotatedClass(Class) - */ - public void setAnnotatedClasses(Class[] annotatedClasses) { - this.annotatedClasses = annotatedClasses; + public void setBeanClassLoader(ClassLoader beanClassLoader) { + delegate.setBeanClassLoader(beanClassLoader); } - /** - * Specify the names of annotated packages, for which package-level - * JDK 1.5+ annotation metadata will be read. - * @see org.hibernate.cfg.AnnotationConfiguration#addPackage(String) - */ - public void setAnnotatedPackages(String[] annotatedPackages) { - this.annotatedPackages = annotatedPackages; + public boolean isSingleton() { + return delegate.isSingleton(); } - /** - * Set whether to use Spring-based scanning for entity classes in the classpath - * instead of listing annotated classes explicitly. - *

Default is none. Specify packages to search for autodetection of your entity - * classes in the classpath. This is analogous to Spring's component-scan feature - * ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}). - */ - public void setPackagesToScan(String[] packagesToScan) { - this.packagesToScan = packagesToScan; + public void afterPropertiesSet() throws Exception { + delegate.afterPropertiesSet(); } - /** - * Specify custom type filters for Spring-based scanning for entity classes. - *

Default is to search all specified packages for classes annotated with - * @javax.persistence.Entity, @javax.persistence.Embeddable - * or @javax.persistence.MappedSuperclass, as well as for - * Hibernate's special @org.hibernate.annotations.Entity. - * @see #setPackagesToScan - */ - public void setEntityTypeFilters(TypeFilter[] entityTypeFilters) { - this.entityTypeFilters = entityTypeFilters; + public DataAccessException translateExceptionIfPossible(RuntimeException ex) { + return delegate.translateExceptionIfPossible(ex); } - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); + public void setJdbcExceptionTranslator( + SQLExceptionTranslator jdbcExceptionTranslator) { + delegate.setJdbcExceptionTranslator(jdbcExceptionTranslator); } + public void setPersistenceExceptionTranslator( + HibernateExceptionTranslator hibernateExceptionTranslator) { + delegate.setPersistenceExceptionTranslator(hibernateExceptionTranslator); + } /** - * Reads metadata from annotated classes and packages into the - * AnnotationConfiguration instance. + * @deprecated as of Spring 3.1 in favor of {@link #scanPackages()} which + * can access the internal {@code AnnotationConfiguration} instance via + * {@link #getConfiguration()}. */ - @Override - protected void postProcessMappings(Configuration config) throws HibernateException { - AnnotationConfiguration annConfig = (AnnotationConfiguration) config; - if (this.annotatedClasses != null) { - for (Class annotatedClass : this.annotatedClasses) { - annConfig.addAnnotatedClass(annotatedClass); - } - } - if (this.annotatedPackages != null) { - for (String annotatedPackage : this.annotatedPackages) { - annConfig.addPackage(annotatedPackage); - } - } - scanPackages(annConfig); + @Deprecated + protected void scanPackages(org.hibernate.cfg.AnnotationConfiguration config) { + this.scanPackages(); } /** - * Perform Spring-based scanning for entity classes. - * @see #setPackagesToScan + * @deprecated as of Spring 3.1 in favor of {@link #newSessionFactory()} which + * can access the internal {@code Configuration} instance via {@link #getConfiguration()}. */ - protected void scanPackages(AnnotationConfiguration config) { - if (this.packagesToScan != null) { - try { - for (String pkg : this.packagesToScan) { - String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + - ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN; - Resource[] resources = this.resourcePatternResolver.getResources(pattern); - MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); - for (Resource resource : resources) { - if (resource.isReadable()) { - MetadataReader reader = readerFactory.getMetadataReader(resource); - String className = reader.getClassMetadata().getClassName(); - if (matchesFilter(reader, readerFactory)) { - config.addAnnotatedClass(this.resourcePatternResolver.getClassLoader().loadClass(className)); - } - } - } - } - } - catch (IOException ex) { - throw new MappingException("Failed to scan classpath for unlisted classes", ex); - } - catch (ClassNotFoundException ex) { - throw new MappingException("Failed to load annotated classes from classpath", ex); - } - } + @Deprecated + protected SessionFactory newSessionFactory(org.hibernate.cfg.Configuration config) throws HibernateException { + return this.newSessionFactory(); } /** - * Check whether any of the configured entity type filters matches - * the current class descriptor contained in the metadata reader. + * @deprecated as of Spring 3.1 in favor of {@link #postProcessMappings()} which + * can access the internal {@code Configuration} instance via {@link #getConfiguration()}. */ - private boolean matchesFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException { - if (this.entityTypeFilters != null) { - for (TypeFilter filter : this.entityTypeFilters) { - if (filter.match(reader, readerFactory)) { - return true; - } - } - } - return false; + @Deprecated + protected void postProcessMappings(org.hibernate.cfg.Configuration config) throws HibernateException { + this.postProcessMappings(); } - /** - * This default implementation delegates to {@link #postProcessAnnotationConfiguration}. + * @deprecated as of Spring 3.1 in favor of {@link #postProcessConfiguration()} which + * can access the internal {@code Configuration} instance via {@link #getConfiguration()}. */ - @Override - protected void postProcessConfiguration(Configuration config) throws HibernateException { - postProcessAnnotationConfiguration((AnnotationConfiguration) config); + @Deprecated + protected void postProcessConfiguration(org.hibernate.cfg.Configuration config) throws HibernateException { + this.postProcessConfiguration(); } /** - * To be implemented by subclasses which want to to perform custom - * post-processing of the AnnotationConfiguration object after this - * FactoryBean performed its default initialization. - *

Note: As of Hibernate 3.6, AnnotationConfiguration's features - * have been rolled into Configuration itself. Simply overriding - * {@link #postProcessConfiguration(org.hibernate.cfg.Configuration)} - * becomes an option as well then. - * @param config the current AnnotationConfiguration object - * @throws HibernateException in case of Hibernate initialization errors + * @deprecated as of Spring 3.1 in favor of {@link #postProcessAnnotationConfiguration()} + * which can access the internal {@code AnnotationConfiguration} instance via + * {@link #getConfiguration()}. */ - protected void postProcessAnnotationConfiguration(AnnotationConfiguration config) throws HibernateException { + @Deprecated + protected void postProcessAnnotationConfiguration(org.hibernate.cfg.AnnotationConfiguration config) throws HibernateException { + this.postProcessAnnotationConfiguration(); } } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBuilder.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBuilder.java new file mode 100644 index 00000000000..af291fb2d81 --- /dev/null +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/annotation/AnnotationSessionFactoryBuilder.java @@ -0,0 +1,300 @@ +/* + * Copyright 2002-2011 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.annotation; + +import java.io.IOException; +import java.lang.reflect.Method; + +import javax.persistence.Embeddable; +import javax.persistence.Entity; +import javax.persistence.MappedSuperclass; +import javax.sql.DataSource; + +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.cfg.AnnotationConfiguration; +import org.hibernate.cfg.Configuration; +import org.springframework.context.annotation.Bean; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.core.type.filter.TypeFilter; +import org.springframework.orm.hibernate3.SessionFactoryBuilderSupport; +import org.springframework.util.ClassUtils; + +/** + * Hibernate {@link AnnotationConfiguration} builder suitable for use within Spring + * {@link org.springframework.context.annotation.Configuration @Configuration} + * class {@link Bean @Bean} methods. For complete details on features, see the + * JavaDoc for the {@link SessionFactoryBuilderSupport} superclass. For use in + * Spring XML configuration, see the {@link AnnotationSessionFactoryBean} subclass. + * + *

As noted in {@code SessionFactoryBuilderSupport} JavaDoc, this class requires + * Hibernate 3.2 or later; it additionally requires that the Java Persistence API + * and Hibernate Annotations add-ons are present. + * + *

Setter methods return the builder instance in order to facilitate + * a concise and convenient method-chaining style. For example: + *

+ * {@code @Configuration}
+ * public class DataConfig {
+ *     {@code @Bean}
+ *     public SessionFactory sessionFactory() {
+ *         return new AnnotationSessionFactoryBuilder()
+ *             .setDataSource(dataSource())
+ *             .setPackagesToScan("com.myco"})
+ *             .buildSessionFactory();
+ *     }
+ * }
+ * 
+ * + *

Most Hibernate configuration operations can be performed directly against + * this API; however you may also access access and configure the underlying + * {@code AnnotationConfiguration} object by using the {@link #doWithConfiguration} + * method and providing a {@code HibernateConfigurationCallback} as follows: + *

+ * SessionFactory sessionFactory =
+ *     new AnnotationSessionFactoryBuilder()
+ *         // ...
+ *         .doWithConfiguration(new HibernateConfigurationCallback<AnnotationConfiguration>() {
+ *             public void configure(AnnotationConfiguration cfg) {
+ *                 cfg.addAnnotatedClass(Foo.class);
+ *             }
+ *          })
+ *         .buildSessionFactory();
+ * 
+ * + * @author Juergen Hoeller + * @author Chris Beams + * @since 3.1 + * @see org.springframework.orm.hibernate3.SessionFactoryBuilderSupport + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder + * @see AnnotationSessionFactoryBean + */ +public class AnnotationSessionFactoryBuilder extends SessionFactoryBuilderSupport { + + /** Hibernate 3.6 consolidates Configuration and AnnotationConfiguration operations. */ + private static final boolean hibernate36Present = ClassUtils.hasMethod(Configuration.class, "addAnnotatedClass", Class.class); + + private static final String RESOURCE_PATTERN = "/**/*.class"; + + private Class[] annotatedClasses; + + private String[] annotatedPackages; + + private String[] packagesToScan; + + private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); + + private TypeFilter[] entityTypeFilters = new TypeFilter[] { + new AnnotationTypeFilter(Entity.class, false), + new AnnotationTypeFilter(Embeddable.class, false), + new AnnotationTypeFilter(MappedSuperclass.class, false), + new AnnotationTypeFilter(org.hibernate.annotations.Entity.class, false)}; + + + /** + * Construct a new {@code AnnotationSessionFactoryBuilder} + */ + public AnnotationSessionFactoryBuilder() { + super(); + } + + /** + * Construct a new {@code AnnotationSessionFactoryBuilder} with the given + * Spring-managed {@code DataSource} instance. + * @see #setDataSource + */ + public AnnotationSessionFactoryBuilder(DataSource dataSource) { + super(dataSource); + } + + /** + * {@inheritDoc} + *

This implementation returns {@link org.hibernate.cfg.Configuration} if + * Hibernate 3.6 or greater is available on the runtime classpath, otherwise + * {@link org.hibernate.cfg.AnnotationConfiguration}. This accommodates + * the consolidation of these two types and deprecation of the latter in + * Hibernate 3.6. + * @see #doWithConfiguration + */ + protected Class getDefaultConfigurationClass() { + return hibernate36Present ? Configuration.class : AnnotationConfiguration.class; + } + + /** + * Set whether to use Spring-based scanning for entity classes in the classpath + * instead of listing annotated classes explicitly. + *

Default is none. Specify packages to search for autodetection of your entity + * classes in the classpath. This is analogous to Spring's component-scan feature + * ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}). + */ + public AnnotationSessionFactoryBuilder setPackagesToScan(String... packagesToScan) { + this.packagesToScan = packagesToScan; + return this; + } + + /** + * Specify annotated classes, for which mappings will be read from + * class-level JDK 1.5+ annotation metadata. + * @see org.hibernate.cfg.AnnotationConfiguration#addAnnotatedClass + */ + public AnnotationSessionFactoryBuilder setAnnotatedClasses(Class... annotatedClasses) { + this.annotatedClasses = annotatedClasses; + return this; + } + + /** + * Specify the names of annotated packages, for which package-level + * JDK 1.5+ annotation metadata will be read. + * @see org.hibernate.cfg.AnnotationConfiguration#addPackage + */ + public AnnotationSessionFactoryBuilder setAnnotatedPackages(String[] annotatedPackages) { + this.annotatedPackages = annotatedPackages; + return this; + } + + /** + * Specify custom type filters for Spring-based scanning for entity classes. + *

Default is to search all specified packages for classes annotated with + * @javax.persistence.Entity, @javax.persistence.Embeddable + * or @javax.persistence.MappedSuperclass, as well as for + * Hibernate's special @org.hibernate.annotations.Entity. + * @see #setPackagesToScan + */ + public AnnotationSessionFactoryBuilder setEntityTypeFilters(TypeFilter[] entityTypeFilters) { + this.entityTypeFilters = entityTypeFilters; + return this; + } + + public void setResourcePatternResolver(ResourcePatternResolver resourcePatternResolver) { + this.resourcePatternResolver = resourcePatternResolver; + } + + /** + * Perform Spring-based scanning for entity classes. + * @see #setPackagesToScan + */ + protected void scanPackages() { + if (this.packagesToScan != null) { + try { + for (String pkg : this.packagesToScan) { + String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + + ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN; + Resource[] resources = this.resourcePatternResolver.getResources(pattern); + MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); + for (Resource resource : resources) { + if (resource.isReadable()) { + MetadataReader reader = readerFactory.getMetadataReader(resource); + String className = reader.getClassMetadata().getClassName(); + if (matchesFilter(reader, readerFactory)) { + Class annotatedClass = this.resourcePatternResolver.getClassLoader().loadClass(className); + invokeConfigurationMethod("addAnnotatedClass", Class.class, annotatedClass); + } + } + } + } + } + catch (IOException ex) { + throw new MappingException("Failed to scan classpath for unlisted classes", ex); + } + catch (ClassNotFoundException ex) { + throw new MappingException("Failed to load annotated classes from classpath", ex); + } + } + } + + /** + * Check whether any of the configured entity type filters matches + * the current class descriptor contained in the metadata reader. + */ + private boolean matchesFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException { + if (this.entityTypeFilters != null) { + for (TypeFilter filter : this.entityTypeFilters) { + if (filter.match(reader, readerFactory)) { + return true; + } + } + } + return false; + } + + /** + * Reads metadata from annotated classes and packages into the + * AnnotationConfiguration instance. + */ + @Override + protected void postProcessMappings() throws HibernateException { + // org.hibernate.cfg.Configuration cfg = getConfiguration(); + if (this.annotatedClasses != null) { + for (Class annotatedClass : this.annotatedClasses) { + invokeConfigurationMethod("addAnnotatedClass", Class.class, annotatedClass); + } + } + if (this.annotatedPackages != null) { + for (String annotatedPackage : this.annotatedPackages) { + invokeConfigurationMethod("addPackage", String.class, annotatedPackage); + } + } + scanPackages(); + } + + /** + * Delegates to {@link #postProcessAnnotationConfiguration}. + */ + @Override + protected void postProcessConfiguration() throws HibernateException { + postProcessAnnotationConfiguration(); + } + + /** + * To be implemented by subclasses which want to to perform custom + * post-processing of the AnnotationConfiguration object after this + * FactoryBean performed its default initialization. + *

Note: As of Hibernate 3.6, AnnotationConfiguration's features + * have been rolled into Configuration itself. Simply overriding + * {@link #postProcessConfiguration(org.hibernate.cfg.Configuration)} + * becomes an option as well then. + * @param config the current AnnotationConfiguration object + * @throws HibernateException in case of Hibernate initialization errors + */ + protected void postProcessAnnotationConfiguration() throws HibernateException { + } + + /** + * Reflectively invoke the given method against the underlying Configuration + * instance. In order to support the consolidation of Hibernate's + * AnnotationConfiguration into Configuration in Hibernate 3.6 while continuing + * to to compile against Hibernate 3.3.x, we must reflectively invoke in order + * to avoid compilation failure. + */ + private void invokeConfigurationMethod(String methodName, Class parameterType, T parameter) { + org.hibernate.cfg.Configuration cfg = getConfiguration(); + try { + Method m = cfg.getClass().getMethod(methodName, parameterType); + m.invoke(cfg, parameter); + } catch (Exception ex) { + throw new IllegalStateException(String.format("Hibernate Configuration class [%s] does not support the '%s(%s)' method.", + cfg.getClass().getSimpleName(), methodName, parameterType.getSimpleName())); + } + } + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/AbstractLobType.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/AbstractLobType.java index 5ab3c68bbbe..3c8fa4ac545 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/AbstractLobType.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/AbstractLobType.java @@ -22,7 +22,6 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import javax.transaction.Status; import javax.transaction.TransactionManager; import org.apache.commons.logging.Log; @@ -30,23 +29,18 @@ import org.apache.commons.logging.LogFactory; import org.hibernate.HibernateException; import org.hibernate.usertype.UserType; import org.hibernate.util.EqualsHelper; - -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.jdbc.support.lob.JtaLobCreatorSynchronization; import org.springframework.jdbc.support.lob.LobCreator; -import org.springframework.jdbc.support.lob.LobHandler; -import org.springframework.jdbc.support.lob.SpringLobCreatorSynchronization; import org.springframework.jdbc.support.lob.LobCreatorUtils; -import org.springframework.orm.hibernate3.LocalSessionFactoryBean; -import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.jdbc.support.lob.LobHandler; +import org.springframework.orm.hibernate3.SessionFactoryBuilderSupport; /** * Abstract base class for Hibernate UserType implementations that map to LOBs. - * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time. + * Retrieves the LobHandler to use from SessionFactoryBuilder at config time. * *

For writing LOBs, either an active Spring transaction synchronization * or an active JTA transaction (with "jtaTransactionManager" specified on - * LocalSessionFactoryBean or a Hibernate TransactionManagerLookup configured + * SessionFactoryBuilder or a Hibernate TransactionManagerLookup configured * through the corresponding Hibernate property) is required. * *

Offers template methods for setting parameters and getting result values, @@ -56,8 +50,8 @@ import org.springframework.transaction.support.TransactionSynchronizationManager * @since 1.2 * @see org.springframework.jdbc.support.lob.LobHandler * @see org.springframework.jdbc.support.lob.LobCreator - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setJtaTransactionManager + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#setLobHandler + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#setJtaTransactionManager */ public abstract class AbstractLobType implements UserType { @@ -70,13 +64,13 @@ public abstract class AbstractLobType implements UserType { /** * Constructor used by Hibernate: fetches config-time LobHandler and - * config-time JTA TransactionManager from LocalSessionFactoryBean. - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager + * config-time JTA TransactionManager from the SessionFactory builder. + * @see org.springframework.orm.hibernate3.SessionFactoryBuilderSupport#getConfigTimeLobHandler + * @see org.springframework.orm.hibernate3.SessionFactoryBuilderSupport#getConfigTimeTransactionManager */ protected AbstractLobType() { - this(LocalSessionFactoryBean.getConfigTimeLobHandler(), - LocalSessionFactoryBean.getConfigTimeTransactionManager()); + this(SessionFactoryBuilderSupport.getConfigTimeLobHandler(), + SessionFactoryBuilderSupport.getConfigTimeTransactionManager()); } /** @@ -150,7 +144,7 @@ public abstract class AbstractLobType implements UserType { if (this.lobHandler == null) { throw new IllegalStateException("No LobHandler found for configuration - " + - "lobHandler property must be set on LocalSessionFactoryBean"); + "lobHandler property must be set on SessionFactoryBuilder"); } try { @@ -172,7 +166,7 @@ public abstract class AbstractLobType implements UserType { if (this.lobHandler == null) { throw new IllegalStateException("No LobHandler found for configuration - " + - "lobHandler property must be set on LocalSessionFactoryBean"); + "lobHandler property must be set on SessionFactoryBuilder"); } LobCreator lobCreator = this.lobHandler.getLobCreator(); diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobByteArrayType.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobByteArrayType.java index c30f81fdb1b..d26b2c26215 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobByteArrayType.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobByteArrayType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005 the original author or authors. + * Copyright 2002-2011 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. @@ -29,7 +29,7 @@ import org.springframework.jdbc.support.lob.LobHandler; /** * Hibernate UserType implementation for byte arrays that get mapped to BLOBs. - * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time. + * Retrieves the LobHandler to use from SessionFactoryBuilder at config time. * *

Can also be defined in generic Hibernate mappings, as DefaultLobCreator will * work with most JDBC-compliant database drivers. In this case, the field type @@ -38,15 +38,15 @@ import org.springframework.jdbc.support.lob.LobHandler; * * @author Juergen Hoeller * @since 1.2 - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#setLobHandler */ public class BlobByteArrayType extends AbstractLobType { /** * Constructor used by Hibernate: fetches config-time LobHandler and - * config-time JTA TransactionManager from LocalSessionFactoryBean. - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager + * config-time JTA TransactionManager from SessionFactoryBuilder. + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#getConfigTimeLobHandler + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#getConfigTimeTransactionManager */ public BlobByteArrayType() { super(); @@ -64,7 +64,7 @@ public class BlobByteArrayType extends AbstractLobType { return new int[] {Types.BLOB}; } - public Class returnedClass() { + public Class returnedClass() { return byte[].class; } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobSerializableType.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobSerializableType.java index 9334c8db88c..ba57c0f778f 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobSerializableType.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobSerializableType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005 the original author or authors. + * Copyright 2002-2011 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. @@ -37,7 +37,7 @@ import org.springframework.jdbc.support.lob.LobHandler; /** * Hibernate UserType implementation for arbitrary objects that get serialized to BLOBs. - * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time. + * Retrieves the LobHandler to use from SessionFactoryBuilder at config time. * *

Can also be defined in generic Hibernate mappings, as DefaultLobCreator will * work with most JDBC-compliant database drivers. In this case, the field type @@ -46,7 +46,7 @@ import org.springframework.jdbc.support.lob.LobHandler; * * @author Juergen Hoeller * @since 1.2 - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#setLobHandler */ public class BlobSerializableType extends AbstractLobType { @@ -60,9 +60,9 @@ public class BlobSerializableType extends AbstractLobType { /** * Constructor used by Hibernate: fetches config-time LobHandler and - * config-time JTA TransactionManager from LocalSessionFactoryBean. - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager + * config-time JTA TransactionManager from SessionFactoryBuilder. + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#getConfigTimeLobHandler + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#getConfigTimeTransactionManager */ public BlobSerializableType() { super(); @@ -80,7 +80,7 @@ public class BlobSerializableType extends AbstractLobType { return new int[] {Types.BLOB}; } - public Class returnedClass() { + public Class returnedClass() { return Serializable.class; } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobStringType.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobStringType.java index be7ac8f15c6..9118906cf9a 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobStringType.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/BlobStringType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 the original author or authors. + * Copyright 2002-2011 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. @@ -29,7 +29,7 @@ import org.springframework.jdbc.support.lob.LobHandler; /** * Hibernate UserType implementation for Strings that get mapped to BLOBs. - * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time. + * Retrieves the LobHandler to use from SessionFactoryBuilder at config time. * *

This is intended for the (arguably unnatural, but still common) case * where character data is stored in a binary LOB. This requires encoding @@ -44,15 +44,15 @@ import org.springframework.jdbc.support.lob.LobHandler; * @author Juergen Hoeller * @since 1.2.7 * @see #getCharacterEncoding() - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#setLobHandler */ public class BlobStringType extends AbstractLobType { /** * Constructor used by Hibernate: fetches config-time LobHandler and - * config-time JTA TransactionManager from LocalSessionFactoryBean. - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager + * config-time JTA TransactionManager from SessionFactoryBuilder. + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#getConfigTimeLobHandler + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#getConfigTimeTransactionManager */ public BlobStringType() { super(); @@ -70,7 +70,7 @@ public class BlobStringType extends AbstractLobType { return new int[] {Types.BLOB}; } - public Class returnedClass() { + public Class returnedClass() { return String.class; } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/ClobStringType.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/ClobStringType.java index 12435ba890c..18ad3478609 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/ClobStringType.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/ClobStringType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005 the original author or authors. + * Copyright 2002-2011 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. @@ -28,7 +28,7 @@ import org.springframework.jdbc.support.lob.LobHandler; /** * Hibernate UserType implementation for Strings that get mapped to CLOBs. - * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time. + * Retrieves the LobHandler to use from SessionFactoryBuilder at config time. * *

Particularly useful for storing Strings with more than 4000 characters in an * Oracle database (only possible via CLOBs), in combination with OracleLobHandler. @@ -40,15 +40,15 @@ import org.springframework.jdbc.support.lob.LobHandler; * * @author Juergen Hoeller * @since 1.2 - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#setLobHandler */ public class ClobStringType extends AbstractLobType { /** * Constructor used by Hibernate: fetches config-time LobHandler and - * config-time JTA TransactionManager from LocalSessionFactoryBean. - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager + * config-time JTA TransactionManager from SessionFactoryBuilder. + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#getConfigTimeLobHandler + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#getConfigTimeTransactionManager */ public ClobStringType() { super(); @@ -66,7 +66,7 @@ public class ClobStringType extends AbstractLobType { return new int[] {Types.CLOB}; } - public Class returnedClass() { + public Class returnedClass() { return String.class; } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/IdTransferringMergeEventListener.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/IdTransferringMergeEventListener.java index 4392b39e9fd..9052419c7e4 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/IdTransferringMergeEventListener.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/IdTransferringMergeEventListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2011 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. @@ -42,19 +42,21 @@ import org.hibernate.persister.entity.EntityPersister; * calls, with the Hibernate SessionFactory configuration specifying an * IdTransferringMergeEventListener. * - *

Typically specified as entry for LocalSessionFactoryBean's "eventListeners" + *

Typically specified as entry for SessionFactoryBuilder's "eventListeners" * map, with key "merge". * * @author Juergen Hoeller * @since 1.2 - * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setEventListeners(java.util.Map) + * @see org.springframework.orm.hibernate3.SessionFactoryBuilder#setEventListeners(java.util.Map) */ +@SuppressWarnings("serial") public class IdTransferringMergeEventListener extends DefaultMergeEventListener { /** * Hibernate 3.1 implementation of ID transferral. */ @Override + @SuppressWarnings("rawtypes") protected void entityIsTransient(MergeEvent event, Map copyCache) { super.entityIsTransient(event, copyCache); SessionImplementor session = event.getSession(); diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/ScopedBeanInterceptor.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/ScopedBeanInterceptor.java index e2bc17731f0..4f24d13573a 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/ScopedBeanInterceptor.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/support/ScopedBeanInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2011 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. @@ -30,18 +30,20 @@ import org.springframework.aop.support.AopUtils; * *

Usage example: * - *

- * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
+ * 
+ * {@code
+ * 
  *   ...
- *   <property name="entityInterceptor">
- *     <bean class="org.springframework.orm.hibernate3.support.ScopedBeanInterceptor"/>
- *   </property>
- * </bean>
+ * + * + * + * }
* * @author Costin Leau * @author Juergen Hoeller * @since 2.0 */ +@SuppressWarnings("serial") public class ScopedBeanInterceptor extends EmptyInterceptor { @Override diff --git a/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/HibernateTransactionManagerTests.java b/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/HibernateTransactionManagerTests.java index 81a4bf6ea46..83b5b6771c0 100644 --- a/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/HibernateTransactionManagerTests.java +++ b/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/HibernateTransactionManagerTests.java @@ -117,7 +117,8 @@ public class HibernateTransactionManagerTests extends TestCase { queryControl.replay(); LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() { - protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { + @Override + protected SessionFactory newSessionFactory() throws HibernateException { return sf; } }; @@ -339,7 +340,8 @@ public class HibernateTransactionManagerTests extends TestCase { queryControl.replay(); LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() { - protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { + @Override + protected SessionFactory newSessionFactory() throws HibernateException { return sf; } }; @@ -416,7 +418,8 @@ public class HibernateTransactionManagerTests extends TestCase { txControl.replay(); LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() { - protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { + @Override + protected SessionFactory newSessionFactory() throws HibernateException { return sf; } }; @@ -770,7 +773,8 @@ public class HibernateTransactionManagerTests extends TestCase { sessionControl.replay(); LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() { - protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { + @Override + protected SessionFactory newSessionFactory() throws HibernateException { return sf; } }; @@ -854,7 +858,8 @@ public class HibernateTransactionManagerTests extends TestCase { txControl.replay(); LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() { - protected SessionFactory newSessionFactory(Configuration config) throws HibernateException { + @Override + protected SessionFactory newSessionFactory() throws HibernateException { return sf; } }; diff --git a/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/LocalSessionFactoryBeanTests.java b/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/LocalSessionFactoryBeanTests.java index c8e4254046c..115502ad0f5 100644 --- a/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/LocalSessionFactoryBeanTests.java +++ b/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/LocalSessionFactoryBeanTests.java @@ -28,9 +28,11 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; + import javax.transaction.TransactionManager; import junit.framework.TestCase; + import org.easymock.MockControl; import org.hibernate.Hibernate; import org.hibernate.HibernateException; @@ -50,7 +52,6 @@ import org.hibernate.engine.FilterDefinition; import org.hibernate.event.MergeEvent; import org.hibernate.event.MergeEventListener; import org.hibernate.mapping.TypeDef; - import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; @@ -59,14 +60,17 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource; /** * @author Juergen Hoeller + * @author Chris Beams * @since 05.03.2005 */ +@SuppressWarnings("serial") public class LocalSessionFactoryBeanTests extends TestCase { public void testLocalSessionFactoryBeanWithDataSource() throws Exception { final DriverManagerDataSource ds = new DriverManagerDataSource(); final List invocations = new ArrayList(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public Configuration addInputStream(InputStream is) { @@ -80,10 +84,11 @@ public class LocalSessionFactoryBeanTests extends TestCase { } }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { assertEquals(LocalDataSourceConnectionProvider.class.getName(), - config.getProperty(Environment.CONNECTION_PROVIDER)); - assertEquals(ds, LocalSessionFactoryBean.getConfigTimeDataSource()); + this.getConfiguration().getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals(ds, SessionFactoryBuilderSupport.getConfigTimeDataSource()); invocations.add("newSessionFactory"); return null; } @@ -98,6 +103,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { final RegionFactory regionFactory = new NoCachingRegionFactory(null); final List invocations = new ArrayList(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public Configuration addInputStream(InputStream is) { @@ -111,10 +117,11 @@ public class LocalSessionFactoryBeanTests extends TestCase { } }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { assertEquals(LocalRegionFactoryProxy.class.getName(), - config.getProperty(Environment.CACHE_REGION_FACTORY)); - assertSame(regionFactory, LocalSessionFactoryBean.getConfigTimeRegionFactory()); + this.getConfiguration().getProperty(Environment.CACHE_REGION_FACTORY)); + assertSame(regionFactory, SessionFactoryBuilderSupport.getConfigTimeRegionFactory()); invocations.add("newSessionFactory"); return null; } @@ -125,10 +132,13 @@ public class LocalSessionFactoryBeanTests extends TestCase { assertEquals("newSessionFactory", invocations.get(0)); } + @SuppressWarnings("deprecation") + // CacheProvider is deprecated in Hibernate 3.3, but LSFB still supports its use public void testLocalSessionFactoryBeanWithCacheProvider() throws Exception { final CacheProvider cacheProvider = new NoCacheProvider(); - final List invocations = new ArrayList(); + final List invocations = new ArrayList(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public Configuration addInputStream(InputStream is) { @@ -143,10 +153,11 @@ public class LocalSessionFactoryBeanTests extends TestCase { }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { assertEquals(LocalCacheProviderProxy.class.getName(), - config.getProperty(Environment.CACHE_PROVIDER)); - assertSame(cacheProvider, LocalSessionFactoryBean.getConfigTimeCacheProvider()); + this.getConfiguration().getProperty(Environment.CACHE_PROVIDER)); + assertSame(cacheProvider, SessionFactoryBeanDelegate.getConfigTimeCacheProvider()); invocations.add("newSessionFactory"); return null; } @@ -161,6 +172,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { final DriverManagerDataSource ds = new DriverManagerDataSource(); final List invocations = new ArrayList(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public Configuration addInputStream(InputStream is) { @@ -175,10 +187,11 @@ public class LocalSessionFactoryBeanTests extends TestCase { }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { assertEquals(TransactionAwareDataSourceConnectionProvider.class.getName(), - config.getProperty(Environment.CONNECTION_PROVIDER)); - assertEquals(ds, LocalSessionFactoryBean.getConfigTimeDataSource()); + this.getConfiguration().getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals(ds, SessionFactoryBuilderSupport.getConfigTimeDataSource()); invocations.add("newSessionFactory"); return null; } @@ -196,6 +209,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { final TransactionManager tm = (TransactionManager) tmControl.getMock(); final List invocations = new ArrayList(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public Configuration addInputStream(InputStream is) { @@ -210,13 +224,14 @@ public class LocalSessionFactoryBeanTests extends TestCase { }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { assertEquals(LocalJtaDataSourceConnectionProvider.class.getName(), - config.getProperty(Environment.CONNECTION_PROVIDER)); - assertEquals(ds, LocalSessionFactoryBean.getConfigTimeDataSource()); + this.getConfiguration().getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals(ds, SessionFactoryBuilderSupport.getConfigTimeDataSource()); assertEquals(LocalTransactionManagerLookup.class.getName(), - config.getProperty(Environment.TRANSACTION_MANAGER_STRATEGY)); - assertEquals(tm, LocalSessionFactoryBean.getConfigTimeTransactionManager()); + this.getConfiguration().getProperty(Environment.TRANSACTION_MANAGER_STRATEGY)); + assertEquals(tm, SessionFactoryBuilderSupport.getConfigTimeTransactionManager()); invocations.add("newSessionFactory"); return null; } @@ -237,6 +252,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { final DriverManagerDataSource ds = new DriverManagerDataSource(); final Set invocations = new HashSet(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public Configuration addJar(File file) { @@ -246,10 +262,11 @@ public class LocalSessionFactoryBeanTests extends TestCase { }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { assertEquals(LocalDataSourceConnectionProvider.class.getName(), - config.getProperty(Environment.CONNECTION_PROVIDER)); - assertEquals(ds, LocalSessionFactoryBean.getConfigTimeDataSource()); + this.getConfiguration().getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals(ds, SessionFactoryBuilderSupport.getConfigTimeDataSource()); invocations.add("newSessionFactory"); return null; } @@ -268,6 +285,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { final DriverManagerDataSource ds = new DriverManagerDataSource(); final Set invocations = new HashSet(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public Configuration addInputStream(InputStream is) { @@ -282,11 +300,12 @@ public class LocalSessionFactoryBeanTests extends TestCase { }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { assertEquals(LocalDataSourceConnectionProvider.class.getName(), - config.getProperty(Environment.CONNECTION_PROVIDER)); - assertEquals(ds, LocalSessionFactoryBean.getConfigTimeDataSource()); - assertEquals("myValue", config.getProperty("myProperty")); + this.getConfiguration().getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals(ds, SessionFactoryBuilderSupport.getConfigTimeDataSource()); + assertEquals("myValue", this.getConfiguration().getProperty("myProperty")); invocations.add("newSessionFactory"); return null; } @@ -307,10 +326,11 @@ public class LocalSessionFactoryBeanTests extends TestCase { public void testLocalSessionFactoryBeanWithValidProperties() throws Exception { final Set invocations = new HashSet(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { assertEquals(UserSuppliedConnectionProvider.class.getName(), - config.getProperty(Environment.CONNECTION_PROVIDER)); - assertEquals("myValue", config.getProperty("myProperty")); + this.getConfiguration().getProperty(Environment.CONNECTION_PROVIDER)); + assertEquals("myValue", this.getConfiguration().getProperty("myProperty")); invocations.add("newSessionFactory"); return null; } @@ -356,7 +376,8 @@ public class LocalSessionFactoryBeanTests extends TestCase { factoryControl.setVoidCallable(1); factoryControl.replay(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { return sessionFactory; } }; @@ -371,6 +392,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { public void testLocalSessionFactoryBeanWithEntityInterceptor() throws Exception { LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public Configuration setInterceptor(Interceptor interceptor) { @@ -397,6 +419,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { public void testLocalSessionFactoryBeanWithNamingStrategy() throws Exception { LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public Configuration setNamingStrategy(NamingStrategy namingStrategy) { @@ -422,6 +445,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { final Properties registeredClassCache = new Properties(); final Properties registeredCollectionCache = new Properties(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public Configuration setCacheConcurrencyStrategy(String clazz, String concurrencyStrategy) { @@ -434,7 +458,8 @@ public class LocalSessionFactoryBeanTests extends TestCase { } }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { return null; } }; @@ -457,6 +482,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { final Properties registeredClassCache = new Properties(); final Properties registeredCollectionCache = new Properties(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { // changed from return type 'void' to 'Configuration' in Hibernate 3.6 @@ -468,7 +494,8 @@ public class LocalSessionFactoryBeanTests extends TestCase { } }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { return null; } }; @@ -490,6 +517,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { public void testLocalSessionFactoryBeanWithEventListeners() throws Exception { final Map registeredListeners = new HashMap(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public void setListener(String type, Object listener) { @@ -497,7 +525,8 @@ public class LocalSessionFactoryBeanTests extends TestCase { } }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { return null; } }; @@ -514,6 +543,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { public void testLocalSessionFactoryBeanWithEventListenerSet() throws Exception { final Map registeredListeners = new HashMap(); LocalSessionFactoryBean sfb = new LocalSessionFactoryBean() { + @Override protected Configuration newConfiguration() { return new Configuration() { public void setListeners(String type, Object[] listeners) { @@ -522,7 +552,8 @@ public class LocalSessionFactoryBeanTests extends TestCase { } }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { return null; } }; @@ -579,6 +610,7 @@ public class LocalSessionFactoryBeanTests extends TestCase { public List registeredFilterDefinitions = new LinkedList(); + @Override protected Configuration newConfiguration() throws HibernateException { return new Configuration() { public void addFilterDefinition(FilterDefinition definition) { @@ -587,7 +619,8 @@ public class LocalSessionFactoryBeanTests extends TestCase { }; } - protected SessionFactory newSessionFactory(Configuration config) { + @Override + protected SessionFactory newSessionFactory() { return null; } } @@ -597,8 +630,9 @@ public class LocalSessionFactoryBeanTests extends TestCase { public Mappings mappings; - protected SessionFactory newSessionFactory(Configuration config) { - this.mappings = config.createMappings(); + @Override + protected SessionFactory newSessionFactory() { + this.mappings = this.getConfiguration().createMappings(); return null; } }