Remove reflection usage in orm.hibernate4.*

Previously reflection was required when interacting with Hibernate 4 in
order to support both Hibernate 3 and Hibernate 4 since there were
non-passive changes in the APIs. Now that the Spring build uses Gradle
it is trivial to support multiple Hibernate versions.

This commit removes the reflection usage in orm.hibernate4.* by
creating a spring-orm-hibernate4 module that uses
gradle/merge-artifacts.gradle to build a single artifact but keep
distinct classpaths.

Issue: SPR-10039
This commit is contained in:
Rob Winch
2012-11-26 12:57:29 -06:00
committed by unknown
parent cf681a809e
commit d7bf56df49
22 changed files with 39 additions and 63 deletions

View File

@@ -1,74 +0,0 @@
/*
* Copyright 2002-2012 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.hibernate4;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import org.hibernate.service.jta.platform.internal.AbstractJtaPlatform;
import org.springframework.transaction.jta.UserTransactionAdapter;
import org.springframework.util.Assert;
/**
* Implementation of Hibernate 4's {@link org.hibernate.service.jta.platform.spi.JtaPlatform}
* SPI, exposing passed-in {@link TransactionManager} and {@link UserTransaction} references.
*
* @author Juergen Hoeller
* @since 3.1.2
*/
class ConfigurableJtaPlatform extends AbstractJtaPlatform {
private final TransactionManager transactionManager;
private final UserTransaction userTransaction;
/**
* Create a new ConfigurableJtaPlatform instance with the given
* JTA TransactionManager and optionally a given UserTransaction.
* @param tm the JTA TransactionManager reference (required)
* @param ut the JTA UserTransaction reference (optional)
*/
public ConfigurableJtaPlatform(TransactionManager tm, UserTransaction ut) {
Assert.notNull(tm, "TransactionManager reference must not be null");
this.transactionManager = tm;
this.userTransaction = (ut != null ? ut : new UserTransactionAdapter(tm));
}
@Override
protected TransactionManager locateTransactionManager() {
return this.transactionManager;
}
@Override
protected UserTransaction locateUserTransaction() {
return this.userTransaction;
}
@Override
protected boolean canCacheTransactionManager() {
return true;
}
@Override
protected boolean canCacheUserTransaction() {
return true;
}
}

View File

@@ -1,59 +0,0 @@
/*
* 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.hibernate4;
import org.hibernate.HibernateException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
/**
* {@link PersistenceExceptionTranslator} capable of translating {@link HibernateException}
* instances to Spring's {@link DataAccessException} hierarchy.
*
* <p>Extended by {@link LocalSessionFactoryBean}, so there is no need to declare this
* translator in addition to a {@code LocalSessionFactoryBean}.
*
* <p>When configuring the container with {@code @Configuration} classes, a {@code @Bean}
* of this type must be registered manually.
*
* @author Juergen Hoeller
* @since 3.1
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
* @see SessionFactoryUtils#convertHibernateAccessException(HibernateException)
*/
public class HibernateExceptionTranslator implements PersistenceExceptionTranslator {
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
* {@code org.springframework.dao} hierarchy.
* @param ex HibernateException that occured
* @return a corresponding DataAccessException
* @see SessionFactoryUtils#convertHibernateAccessException
*/
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
return SessionFactoryUtils.convertHibernateAccessException(ex);
}
}

View File

@@ -1,54 +0,0 @@
/*
* 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.hibernate4;
import java.sql.SQLException;
import org.hibernate.JDBCException;
import org.springframework.dao.UncategorizedDataAccessException;
/**
* Hibernate-specific subclass of UncategorizedDataAccessException,
* for JDBC exceptions that Hibernate wrapped.
*
* @author Juergen Hoeller
* @since 3.1
* @see SessionFactoryUtils#convertHibernateAccessException
*/
public class HibernateJdbcException extends UncategorizedDataAccessException {
public HibernateJdbcException(JDBCException ex) {
super("JDBC exception on Hibernate data access: SQLException for SQL [" + ex.getSQL() + "]; SQL state [" +
ex.getSQLState() + "]; error code [" + ex.getErrorCode() + "]; " + ex.getMessage(), ex);
}
/**
* Return the underlying SQLException.
*/
public SQLException getSQLException() {
return ((JDBCException) getCause()).getSQLException();
}
/**
* Return the SQL that led to the problem.
*/
public String getSql() {
return ((JDBCException) getCause()).getSQL();
}
}

View File

@@ -1,42 +0,0 @@
/*
* 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.hibernate4;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.WrongClassException;
import org.springframework.orm.ObjectRetrievalFailureException;
/**
* Hibernate-specific subclass of ObjectRetrievalFailureException.
* Converts Hibernate's UnresolvableObjectException and WrongClassException.
*
* @author Juergen Hoeller
* @since 3.1
* @see SessionFactoryUtils#convertHibernateAccessException
*/
public class HibernateObjectRetrievalFailureException extends ObjectRetrievalFailureException {
public HibernateObjectRetrievalFailureException(UnresolvableObjectException ex) {
super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
}
public HibernateObjectRetrievalFailureException(WrongClassException ex) {
super(ex.getEntityName(), ex.getIdentifier(), ex.getMessage(), ex);
}
}

View File

@@ -1,42 +0,0 @@
/*
* 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.hibernate4;
import org.hibernate.StaleObjectStateException;
import org.hibernate.StaleStateException;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
/**
* Hibernate-specific subclass of ObjectOptimisticLockingFailureException.
* Converts Hibernate's StaleObjectStateException and StaleStateException.
*
* @author Juergen Hoeller
* @since 3.1
* @see SessionFactoryUtils#convertHibernateAccessException
*/
public class HibernateOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
public HibernateOptimisticLockingFailureException(StaleObjectStateException ex) {
super(ex.getEntityName(), ex.getIdentifier(), ex);
}
public HibernateOptimisticLockingFailureException(StaleStateException ex) {
super(ex.getMessage(), ex);
}
}

View File

@@ -1,44 +0,0 @@
/*
* 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.hibernate4;
import org.hibernate.QueryException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* Hibernate-specific subclass of InvalidDataAccessResourceUsageException,
* thrown on invalid HQL query syntax.
*
* @author Juergen Hoeller
* @since 3.1
* @see SessionFactoryUtils#convertHibernateAccessException
*/
public class HibernateQueryException extends InvalidDataAccessResourceUsageException {
public HibernateQueryException(QueryException ex) {
super(ex.getMessage(), ex);
}
/**
* Return the HQL query string that was invalid.
*/
public String getQueryString() {
return ((QueryException) getCause()).getQueryString();
}
}

View File

@@ -1,43 +0,0 @@
/*
* 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.hibernate4;
import org.hibernate.HibernateException;
import org.springframework.dao.UncategorizedDataAccessException;
/**
* Hibernate-specific subclass of UncategorizedDataAccessException,
* for Hibernate system errors that do not match any concrete
* <code>org.springframework.dao</code> exceptions.
*
* @author Juergen Hoeller
* @since 3.1
* @see SessionFactoryUtils#convertHibernateAccessException
*/
public class HibernateSystemException extends UncategorizedDataAccessException {
/**
* Create a new HibernateSystemException,
* wrapping an arbitrary HibernateException.
* @param cause the HibernateException thrown
*/
public HibernateSystemException(HibernateException cause) {
super(cause != null ? cause.getMessage() : null, cause);
}
}

View File

@@ -1,708 +0,0 @@
/*
* 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.hibernate4;
import java.lang.reflect.Method;
import java.sql.Connection;
import javax.sql.DataSource;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.transaction.spi.TransactionContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.InvalidIsolationLevelException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.ResourceTransactionManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* {@link org.springframework.transaction.PlatformTransactionManager}
* implementation for a single Hibernate {@link org.hibernate.SessionFactory}.
* Binds a Hibernate Session from the specified factory to the thread,
* potentially allowing for one thread-bound Session per factory.
* <code>SessionFactory.getCurrentSession()</code> is required for Hibernate
* access code that needs to support this transaction handling mechanism,
* with the SessionFactory being configured with {@link SpringSessionContext}.
*
* <p>Supports custom isolation levels, and timeouts that get applied as
* Hibernate transaction timeouts.
*
* <p>This transaction manager is appropriate for applications that use a single
* Hibernate SessionFactory for transactional data access, but it also supports
* direct DataSource access within a transaction (i.e. plain JDBC code working
* with the same DataSource). This allows for mixing services which access Hibernate
* and services which use plain JDBC (without being aware of Hibernate)!
* Application code needs to stick to the same simple Connection lookup pattern as
* with {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
* (i.e. {@link org.springframework.jdbc.datasource.DataSourceUtils#getConnection}
* or going through a
* {@link org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy}).
*
* <p>Note: To be able to register a DataSource's Connection for plain JDBC code,
* this instance needs to be aware of the DataSource ({@link #setDataSource}).
* The given DataSource should obviously match the one used by the given SessionFactory.
*
* <p>JTA (usually through {@link org.springframework.transaction.jta.JtaTransactionManager})
* is necessary for accessing multiple transactional resources within the same
* transaction. The DataSource that Hibernate uses needs to be JTA-enabled in
* such a scenario (see container setup).
*
* <p>On JDBC 3.0, this transaction manager supports nested transactions via JDBC 3.0
* Savepoints. The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"}
* flag defaults to "false", though, as nested transactions will just apply to the
* JDBC Connection, not to the Hibernate Session and its cached objects. You can
* manually set the flag to "true" if you want to use nested transactions for
* JDBC access code which participates in Hibernate transactions (provided that
* your JDBC driver supports Savepoints). <i>Note that Hibernate itself does not
* support nested transactions! Hence, do not expect Hibernate access code to
* semantically participate in a nested transaction.</i>
*
* @author Juergen Hoeller
* @since 3.1
* @see #setSessionFactory
* @see #setDataSource
* @see org.hibernate.SessionFactory#getCurrentSession()
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
* @see org.springframework.jdbc.core.JdbcTemplate
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
* @see org.springframework.transaction.jta.JtaTransactionManager
*/
@SuppressWarnings("serial")
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
/**
* A Method handle for the <code>SessionFactory.getCurrentSession()</code> method.
* The return value differs between Hibernate 3.x and 4.x; for cross-compilation purposes,
* we have to use reflection here as long as we keep compiling against Hibernate 3.x jars.
*/
private static final Method getCurrentSessionMethod =
ClassUtils.getMethod(SessionFactory.class, "getCurrentSession");
private SessionFactory sessionFactory;
private DataSource dataSource;
private boolean autodetectDataSource = true;
private boolean prepareConnection = true;
private boolean hibernateManagedSession = false;
/**
* Create a new HibernateTransactionManager instance.
* A SessionFactory has to be set to be able to use it.
* @see #setSessionFactory
*/
public HibernateTransactionManager() {
}
/**
* Create a new HibernateTransactionManager instance.
* @param sessionFactory SessionFactory to manage transactions for
*/
public HibernateTransactionManager(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
afterPropertiesSet();
}
/**
* Set the SessionFactory that this instance should manage transactions for.
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* Return the SessionFactory that this instance should manage transactions for.
*/
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
/**
* Set the JDBC DataSource that this instance should manage transactions for.
* The DataSource should match the one used by the Hibernate SessionFactory:
* for example, you could specify the same JNDI DataSource for both.
* <p>If the SessionFactory was configured with LocalDataSourceConnectionProvider,
* 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.
* <p>A transactional JDBC Connection for this DataSource will be provided to
* application code accessing this DataSource directly via DataSourceUtils
* or JdbcTemplate. The Connection will be taken from the Hibernate Session.
* <p>The DataSource specified here should be the target DataSource to manage
* transactions for, not a TransactionAwareDataSourceProxy. Only data access
* code may work with TransactionAwareDataSourceProxy, while the transaction
* manager needs to work on the underlying target DataSource. If there's
* nevertheless a TransactionAwareDataSourceProxy passed in, it will be
* unwrapped to extract its target DataSource.
* @see #setAutodetectDataSource
* @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
* @see org.springframework.jdbc.datasource.DataSourceUtils
* @see org.springframework.jdbc.core.JdbcTemplate
*/
public void setDataSource(DataSource dataSource) {
if (dataSource instanceof TransactionAwareDataSourceProxy) {
// If we got a TransactionAwareDataSourceProxy, we need to perform transactions
// for its underlying target DataSource, else data access code won't see
// properly exposed transactions (i.e. transactions for the target DataSource).
this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
}
else {
this.dataSource = dataSource;
}
}
/**
* Return the JDBC DataSource that this instance manages transactions for.
*/
public DataSource getDataSource() {
return this.dataSource;
}
/**
* Set whether to autodetect a JDBC DataSource used by the Hibernate SessionFactory,
* if set via SessionFactoryBuilder's <code>setDataSource</code>. Default is "true".
* <p>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
*/
public void setAutodetectDataSource(boolean autodetectDataSource) {
this.autodetectDataSource = autodetectDataSource;
}
/**
* Set whether to prepare the underlying JDBC Connection of a transactional
* Hibernate Session, that is, whether to apply a transaction-specific
* isolation level and/or the transaction's read-only flag to the underlying
* JDBC Connection.
* <p>Default is "true". If you turn this flag off, the transaction manager
* will not support per-transaction isolation levels anymore. It will not
* call <code>Connection.setReadOnly(true)</code> for read-only transactions
* anymore either. If this flag is turned off, no cleanup of a JDBC Connection
* is required after a transaction, since no Connection settings will get modified.
* @see java.sql.Connection#setTransactionIsolation
* @see java.sql.Connection#setReadOnly
*/
public void setPrepareConnection(boolean prepareConnection) {
this.prepareConnection = prepareConnection;
}
/**
* Set whether to operate on a Hibernate-managed Session instead of a
* Spring-managed Session, that is, whether to obtain the Session through
* Hibernate's {@link org.hibernate.SessionFactory#getCurrentSession()}
* instead of {@link org.hibernate.SessionFactory#openSession()} (with a Spring
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}
* check preceding it).
* <p>Default is "false", i.e. using a Spring-managed Session: taking the current
* thread-bound Session if available (e.g. in an Open-Session-in-View scenario),
* creating a new Session for the current transaction otherwise.
* <p>Switch this flag to "true" in order to enforce use of a Hibernate-managed Session.
* Note that this requires {@link org.hibernate.SessionFactory#getCurrentSession()}
* to always return a proper Session when called for a Spring-managed transaction;
* transaction begin will fail if the <code>getCurrentSession()</code> call fails.
* <p>This mode will typically be used in combination with a custom Hibernate
* {@link org.hibernate.context.CurrentSessionContext} implementation that stores
* Sessions in a place other than Spring's TransactionSynchronizationManager.
* It may also be used in combination with Spring's Open-Session-in-View support
* (using Spring's default {@link SpringSessionContext}), in which case it subtly
* differs from the Spring-managed Session mode: The pre-bound Session will <i>not</i>
* receive a <code>clear()</code> call (on rollback) or a <code>disconnect()</code>
* call (on transaction completion) in such a scenario; this is rather left up
* to a custom CurrentSessionContext implementation (if desired).
*/
public void setHibernateManagedSession(boolean hibernateManagedSession) {
this.hibernateManagedSession = hibernateManagedSession;
}
public void afterPropertiesSet() {
if (getSessionFactory() == null) {
throw new IllegalArgumentException("Property 'sessionFactory' is required");
}
// Check for SessionFactory's DataSource.
if (this.autodetectDataSource && getDataSource() == null) {
DataSource sfds = SessionFactoryUtils.getDataSource(getSessionFactory());
if (sfds != null) {
// Use the SessionFactory's DataSource for exposing transactions to JDBC code.
if (logger.isInfoEnabled()) {
logger.info("Using DataSource [" + sfds +
"] of Hibernate SessionFactory for HibernateTransactionManager");
}
setDataSource(sfds);
}
}
}
public Object getResourceFactory() {
return getSessionFactory();
}
@Override
protected Object doGetTransaction() {
HibernateTransactionObject txObject = new HibernateTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
if (sessionHolder != null) {
if (logger.isDebugEnabled()) {
logger.debug("Found thread-bound Session [" + sessionHolder.getSession() + "] for Hibernate transaction");
}
txObject.setSessionHolder(sessionHolder);
}
else if (this.hibernateManagedSession) {
try {
Session session = (Session) ReflectionUtils.invokeMethod(getCurrentSessionMethod, this.sessionFactory);
if (logger.isDebugEnabled()) {
logger.debug("Found Hibernate-managed Session [" + session + "] for Spring-managed transaction");
}
txObject.setExistingSession(session);
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException(
"Could not obtain Hibernate-managed Session for Spring-managed transaction", ex);
}
}
if (getDataSource() != null) {
ConnectionHolder conHolder = (ConnectionHolder)
TransactionSynchronizationManager.getResource(getDataSource());
txObject.setConnectionHolder(conHolder);
}
return txObject;
}
@Override
protected boolean isExistingTransaction(Object transaction) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
return (txObject.hasSpringManagedTransaction() ||
(this.hibernateManagedSession && txObject.hasHibernateManagedTransaction()));
}
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
throw new IllegalTransactionStateException(
"Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +
"running within DataSourceTransactionManager if told to manage the DataSource itself. " +
"It is recommended to use a single HibernateTransactionManager for all transactions " +
"on a single DataSource, no matter whether Hibernate or JDBC access.");
}
Session session = null;
try {
if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
Session newSession = SessionFactoryUtils.openSession(getSessionFactory());
if (logger.isDebugEnabled()) {
logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
}
txObject.setSession(newSession);
}
session = txObject.getSessionHolder().getSession();
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
// We're allowed to change the transaction settings of the JDBC Connection.
if (logger.isDebugEnabled()) {
logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
}
Connection con = ((SessionImplementor) session).connection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
}
else {
// Not allowed to change the transaction settings of the JDBC Connection.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
// We should set a specific isolation level but are not allowed to...
throw new InvalidIsolationLevelException(
"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).");
}
if (logger.isDebugEnabled()) {
logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
}
}
if (definition.isReadOnly() && txObject.isNewSession()) {
// Just set to NEVER in case of a new Session for this transaction.
session.setFlushMode(FlushMode.MANUAL);
}
if (!definition.isReadOnly() && !txObject.isNewSession()) {
// We need AUTO or COMMIT for a non-read-only transaction.
FlushMode flushMode = session.getFlushMode();
if (FlushMode.isManualFlushMode(session.getFlushMode())) {
session.setFlushMode(FlushMode.AUTO);
txObject.getSessionHolder().setPreviousFlushMode(flushMode);
}
}
Transaction hibTx;
// Register transaction timeout.
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1+
// Applies to all statements, also to inserts, updates and deletes!
hibTx = session.getTransaction();
hibTx.setTimeout(timeout);
hibTx.begin();
}
else {
// Open a plain Hibernate transaction without specified timeout.
hibTx = session.beginTransaction();
}
// Add the Hibernate transaction to the session holder.
txObject.getSessionHolder().setTransaction(hibTx);
// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
if (getDataSource() != null) {
Connection con = ((SessionImplementor) session).connection();
ConnectionHolder conHolder = new ConnectionHolder(con);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
conHolder.setTimeoutInSeconds(timeout);
}
if (logger.isDebugEnabled()) {
logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
}
TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
txObject.setConnectionHolder(conHolder);
}
// Bind the session holder to the thread.
if (txObject.isNewSessionHolder()) {
TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
}
txObject.getSessionHolder().setSynchronizedWithTransaction(true);
}
catch (Exception ex) {
if (txObject.isNewSession()) {
try {
if (session.getTransaction().isActive()) {
session.getTransaction().rollback();
}
}
catch (Throwable ex2) {
logger.debug("Could not rollback Session after failed transaction begin", ex);
}
finally {
SessionFactoryUtils.closeSession(session);
}
}
throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
}
}
@Override
protected Object doSuspend(Object transaction) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
txObject.setSessionHolder(null);
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
txObject.setConnectionHolder(null);
ConnectionHolder connectionHolder = null;
if (getDataSource() != null) {
connectionHolder = (ConnectionHolder) TransactionSynchronizationManager.unbindResource(getDataSource());
}
return new SuspendedResourcesHolder(sessionHolder, connectionHolder);
}
@Override
protected void doResume(Object transaction, Object suspendedResources) {
SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
// From non-transactional code running in active transaction synchronization
// -> can be safely removed, will be closed on transaction completion.
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
TransactionSynchronizationManager.bindResource(getSessionFactory(), resourcesHolder.getSessionHolder());
if (getDataSource() != null) {
TransactionSynchronizationManager.bindResource(getDataSource(), resourcesHolder.getConnectionHolder());
}
}
@Override
protected void doCommit(DefaultTransactionStatus status) {
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Committing Hibernate transaction on Session [" +
txObject.getSessionHolder().getSession() + "]");
}
try {
txObject.getSessionHolder().getTransaction().commit();
}
catch (org.hibernate.TransactionException ex) {
// assumably from commit call to the underlying JDBC connection
throw new TransactionSystemException("Could not commit Hibernate transaction", ex);
}
catch (HibernateException ex) {
// assumably failed to flush changes to database
throw convertHibernateAccessException(ex);
}
}
@Override
protected void doRollback(DefaultTransactionStatus status) {
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Rolling back Hibernate transaction on Session [" +
txObject.getSessionHolder().getSession() + "]");
}
try {
txObject.getSessionHolder().getTransaction().rollback();
}
catch (org.hibernate.TransactionException ex) {
throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
}
catch (HibernateException ex) {
// Shouldn't really happen, as a rollback doesn't cause a flush.
throw convertHibernateAccessException(ex);
}
finally {
if (!txObject.isNewSession() && !this.hibernateManagedSession) {
// Clear all pending inserts/updates/deletes in the Session.
// Necessary for pre-bound Sessions, to avoid inconsistent state.
txObject.getSessionHolder().getSession().clear();
}
}
}
@Override
protected void doSetRollbackOnly(DefaultTransactionStatus status) {
HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
if (status.isDebug()) {
logger.debug("Setting Hibernate transaction on Session [" +
txObject.getSessionHolder().getSession() + "] rollback-only");
}
txObject.setRollbackOnly();
}
@Override
protected void doCleanupAfterCompletion(Object transaction) {
HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
// Remove the session holder from the thread.
if (txObject.isNewSessionHolder()) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
// Remove the JDBC connection holder from the thread, if exposed.
if (getDataSource() != null) {
TransactionSynchronizationManager.unbindResource(getDataSource());
}
Session session = txObject.getSessionHolder().getSession();
if (this.prepareConnection && session.isConnected() && isSameConnectionForEntireSession(session)) {
// We're running with connection release mode "on_close": We're able to reset
// 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 {
Connection con = ((SessionImplementor) session).connection();
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
}
catch (HibernateException ex) {
logger.debug("Could not access JDBC Connection of Hibernate Session", ex);
}
}
if (txObject.isNewSession()) {
if (logger.isDebugEnabled()) {
logger.debug("Closing Hibernate Session [" + session + "] after transaction");
}
SessionFactoryUtils.closeSession(session);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction");
}
if (txObject.getSessionHolder().getPreviousFlushMode() != null) {
session.setFlushMode(txObject.getSessionHolder().getPreviousFlushMode());
}
if (!this.hibernateManagedSession) {
session.disconnect();
}
}
txObject.getSessionHolder().clear();
}
/**
* Return whether the given Hibernate Session will always hold the same
* JDBC Connection. This is used to check whether the transaction manager
* can safely prepare and clean up the JDBC Connection used for a transaction.
* <p>The default implementation checks the Session's connection release mode
* to be "on_close".
* @param session the Hibernate Session to check
* @see org.hibernate.engine.transaction.spi.TransactionContext#getConnectionReleaseMode()
* @see org.hibernate.ConnectionReleaseMode#ON_CLOSE
*/
protected boolean isSameConnectionForEntireSession(Session session) {
if (!(session instanceof TransactionContext)) {
// The best we can do is to assume we're safe.
return true;
}
ConnectionReleaseMode releaseMode = ((TransactionContext) session).getConnectionReleaseMode();
return ConnectionReleaseMode.ON_CLOSE.equals(releaseMode);
}
/**
* Convert the given HibernateException to an appropriate exception
* from the <code>org.springframework.dao</code> hierarchy.
* <p>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
*/
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
return SessionFactoryUtils.convertHibernateAccessException(ex);
}
/**
* Hibernate transaction object, representing a SessionHolder.
* Used as transaction object by HibernateTransactionManager.
*/
private class HibernateTransactionObject extends JdbcTransactionObjectSupport {
private SessionHolder sessionHolder;
private boolean newSessionHolder;
private boolean newSession;
public void setSession(Session session) {
this.sessionHolder = new SessionHolder(session);
this.newSessionHolder = true;
this.newSession = true;
}
public void setExistingSession(Session session) {
this.sessionHolder = new SessionHolder(session);
this.newSessionHolder = true;
this.newSession = false;
}
public void setSessionHolder(SessionHolder sessionHolder) {
this.sessionHolder = sessionHolder;
this.newSessionHolder = false;
this.newSession = false;
}
public SessionHolder getSessionHolder() {
return this.sessionHolder;
}
public boolean isNewSessionHolder() {
return this.newSessionHolder;
}
public boolean isNewSession() {
return this.newSession;
}
public boolean hasSpringManagedTransaction() {
return (this.sessionHolder != null && this.sessionHolder.getTransaction() != null);
}
public boolean hasHibernateManagedTransaction() {
return (this.sessionHolder != null && this.sessionHolder.getSession().getTransaction().isActive());
}
public void setRollbackOnly() {
this.sessionHolder.setRollbackOnly();
if (hasConnectionHolder()) {
getConnectionHolder().setRollbackOnly();
}
}
public boolean isRollbackOnly() {
return this.sessionHolder.isRollbackOnly() ||
(hasConnectionHolder() && getConnectionHolder().isRollbackOnly());
}
@Override
public void flush() {
try {
this.sessionHolder.getSession().flush();
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
}
}
/**
* Holder for suspended resources.
* Used internally by <code>doSuspend</code> and <code>doResume</code>.
*/
private static class SuspendedResourcesHolder {
private final SessionHolder sessionHolder;
private final ConnectionHolder connectionHolder;
private SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder) {
this.sessionHolder = sessionHolder;
this.connectionHolder = conHolder;
}
private SessionHolder getSessionHolder() {
return this.sessionHolder;
}
private ConnectionHolder getConnectionHolder() {
return this.connectionHolder;
}
}
}

View File

@@ -1,405 +0,0 @@
/*
* Copyright 2002-2012 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.hibernate4;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.Interceptor;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.NamingStrategy;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ClassPathResource;
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;
/**
* {@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 data access objects via dependency injection.
*
* <p><b>NOTE:</b> This variant of LocalSessionFactoryBean requires Hibernate 4.0 or higher.
* It is similar in role to the same-named class in the <code>orm.hibernate3</code> package.
* However, in practice, it is closer to <code>AnnotationSessionFactoryBean</code> since
* its core purpose is to bootstrap a <code>SessionFactory</code> from annotation scanning.
*
* <p><b>NOTE:</b> To set up Hibernate 4 for Spring-driven JTA transactions, make
* sure to either specify the {@link #setJtaTransactionManager "jtaTransactionManager"}
* bean property or to set the "hibernate.transaction.factory_class" property to
* {@link org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory}.
* Otherwise, Hibernate's smart flushing mechanism won't work properly.
*
* @author Juergen Hoeller
* @since 3.1
* @see #setDataSource
* @see #setPackagesToScan
*/
public class LocalSessionFactoryBean extends HibernateExceptionTranslator
implements FactoryBean<SessionFactory>, ResourceLoaderAware, InitializingBean, DisposableBean {
private DataSource dataSource;
private Resource[] configLocations;
private String[] mappingResources;
private Resource[] mappingLocations;
private Resource[] cacheableMappingLocations;
private Resource[] mappingJarLocations;
private Resource[] mappingDirectoryLocations;
private Interceptor entityInterceptor;
private NamingStrategy namingStrategy;
private Properties hibernateProperties;
private Class<?>[] annotatedClasses;
private String[] annotatedPackages;
private String[] packagesToScan;
private Object jtaTransactionManager;
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private Configuration configuration;
private SessionFactory sessionFactory;
/**
* Set the DataSource to be used by the SessionFactory.
* If set, this will override corresponding settings in Hibernate properties.
* <p>If this is set, the Hibernate settings should not define
* a connection provider to avoid meaningless double configuration.
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Set the location of a single Hibernate XML config file, for example as
* classpath resource "classpath:hibernate.cfg.xml".
* <p>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".
* <p>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.
* <p>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.
* <p>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.
* <p>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".
* <p>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".
* <p>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 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.
* @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;
}
/**
* Set Hibernate properties, such as "hibernate.dialect".
* <p>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;
}
/**
* Specify annotated entity classes to register with this Hibernate SessionFactory.
* @see org.hibernate.cfg.Configuration#addAnnotatedClass(Class)
*/
public void setAnnotatedClasses(Class<?>[] annotatedClasses) {
this.annotatedClasses = annotatedClasses;
}
/**
* Specify the names of annotated packages, for which package-level
* annotation metadata will be read.
* @see org.hibernate.cfg.Configuration#addPackage(String)
*/
public void setAnnotatedPackages(String[] annotatedPackages) {
this.annotatedPackages = annotatedPackages;
}
/**
* 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;
}
/**
* Set the Spring {@link org.springframework.transaction.jta.JtaTransactionManager}
* or the JTA {@link javax.transaction.TransactionManager} to be used with Hibernate,
* if any.
* @see LocalSessionFactoryBuilder#setJtaTransactionManager
*/
public void setJtaTransactionManager(Object jtaTransactionManager) {
this.jtaTransactionManager = jtaTransactionManager;
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
}
public void afterPropertiesSet() throws IOException {
LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(this.dataSource, this.resourcePatternResolver);
if (this.configLocations != null) {
for (Resource resource : this.configLocations) {
// Load Hibernate configuration from given location.
sfb.configure(resource.getURL());
}
}
if (this.mappingResources != null) {
// Register given Hibernate mapping definitions, contained in resource files.
for (String mapping : this.mappingResources) {
Resource mr = new ClassPathResource(mapping.trim(), this.resourcePatternResolver.getClassLoader());
sfb.addInputStream(mr.getInputStream());
}
}
if (this.mappingLocations != null) {
// Register given Hibernate mapping definitions, contained in resource files.
for (Resource resource : this.mappingLocations) {
sfb.addInputStream(resource.getInputStream());
}
}
if (this.cacheableMappingLocations != null) {
// Register given cacheable Hibernate mapping definitions, read from the file system.
for (Resource resource : this.cacheableMappingLocations) {
sfb.addCacheableFile(resource.getFile());
}
}
if (this.mappingJarLocations != null) {
// Register given Hibernate mapping definitions, contained in jar files.
for (Resource resource : this.mappingJarLocations) {
sfb.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");
}
sfb.addDirectory(file);
}
}
if (this.entityInterceptor != null) {
sfb.setInterceptor(this.entityInterceptor);
}
if (this.namingStrategy != null) {
sfb.setNamingStrategy(this.namingStrategy);
}
if (this.hibernateProperties != null) {
sfb.addProperties(this.hibernateProperties);
}
if (this.annotatedClasses != null) {
sfb.addAnnotatedClasses(this.annotatedClasses);
}
if (this.annotatedPackages != null) {
sfb.addPackages(this.annotatedPackages);
}
if (this.packagesToScan != null) {
sfb.scanPackages(this.packagesToScan);
}
if (this.jtaTransactionManager != null) {
sfb.setJtaTransactionManager(this.jtaTransactionManager);
}
// Build SessionFactory instance.
this.configuration = sfb;
this.sessionFactory = buildSessionFactory(sfb);
}
/**
* 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.
* <p>The default implementation invokes LocalSessionFactoryBuilder's buildSessionFactory.
* A custom implementation could prepare the instance in a specific way (e.g. applying
* a custom ServiceRegistry) or use a custom SessionFactoryImpl subclass.
* @param sfb LocalSessionFactoryBuilder prepared by this LocalSessionFactoryBean
* @return the SessionFactory instance
* @see LocalSessionFactoryBuilder#buildSessionFactory
*/
protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
return sfb.buildSessionFactory();
}
/**
* Return the Hibernate Configuration object used to build the SessionFactory.
* Allows for 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 SessionFactory getObject() {
return this.sessionFactory;
}
public Class<?> getObjectType() {
return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class);
}
public boolean isSingleton() {
return true;
}
public void destroy() {
this.sessionFactory.close();
}
}

View File

@@ -1,260 +0,0 @@
/*
* Copyright 2002-2012 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.hibernate4;
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 javax.transaction.TransactionManager;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory;
import org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform;
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.transaction.jta.JtaTransactionManager;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* A Spring-provided extension of the standard Hibernate {@link Configuration} class,
* adding {@link SpringSessionContext} as a default and providing convenient ways
* to specify a DataSource and an application class loader.
*
* <p>This is designed for programmatic use, e.g. in {@code @Bean} factory methods.
* Consider using {@link LocalSessionFactoryBean} for XML bean definition files.
*
* <p><b>NOTE:</b> To set up Hibernate 4 for Spring-driven JTA transactions, make
* sure to either use the {@link #setJtaTransactionManager} method or to set the
* "hibernate.transaction.factory_class" property to {@link CMTTransactionFactory}.
* Otherwise, Hibernate's smart flushing mechanism won't work properly.
*
* @author Juergen Hoeller
* @since 3.1
* @see LocalSessionFactoryBean
*/
@SuppressWarnings("serial")
public class LocalSessionFactoryBuilder extends Configuration {
private static final String RESOURCE_PATTERN = "/**/*.class";
private static final TypeFilter[] ENTITY_TYPE_FILTERS = new TypeFilter[] {
new AnnotationTypeFilter(Entity.class, false),
new AnnotationTypeFilter(Embeddable.class, false),
new AnnotationTypeFilter(MappedSuperclass.class, false)};
private static final Method addAnnotatedClassMethod =
ClassUtils.getMethod(Configuration.class, "addAnnotatedClass", Class.class);
private static final Method addPackageMethod =
ClassUtils.getMethod(Configuration.class, "addPackage", String.class);
private final ResourcePatternResolver resourcePatternResolver;
/**
* Create a new LocalSessionFactoryBuilder for the given DataSource.
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be <code>null</code>)
*/
public LocalSessionFactoryBuilder(DataSource dataSource) {
this(dataSource, new PathMatchingResourcePatternResolver());
}
/**
* Create a new LocalSessionFactoryBuilder for the given DataSource.
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be <code>null</code>)
* @param classLoader the ClassLoader to load application classes from
*/
public LocalSessionFactoryBuilder(DataSource dataSource, ClassLoader classLoader) {
this(dataSource, new PathMatchingResourcePatternResolver(classLoader));
}
/**
* Create a new LocalSessionFactoryBuilder for the given DataSource.
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be <code>null</code>)
* @param resourceLoader the ResourceLoader to load application classes from
*/
public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader) {
getProperties().put(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());
if (dataSource != null) {
getProperties().put(Environment.DATASOURCE, dataSource);
}
getProperties().put(AvailableSettings.APP_CLASSLOADER, resourceLoader.getClassLoader());
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
}
/**
* Set the Spring {@link JtaTransactionManager} or the JTA {@link TransactionManager}
* to be used with Hibernate, if any. Allows for using a Spring-managed transaction
* manager for Hibernate 4's session and cache synchronization, with the
* "hibernate.transaction.jta.platform" automatically set to it. Also sets
* "hibernate.transaction.factory_class" to {@link CMTTransactionFactory},
* instructing Hibernate to interact with externally managed transactions.
* <p>A passed-in Spring {@link JtaTransactionManager} needs to contain a JTA
* {@link TransactionManager} reference to be usable here, except for the WebSphere
* case where we'll automatically set {@link WebSphereExtendedJtaPlatform} accordingly.
* <p>Note: If this is set, the Hibernate settings should not contain a JTA platform
* setting to avoid meaningless double configuration.
*/
public LocalSessionFactoryBuilder setJtaTransactionManager(Object jtaTransactionManager) {
Assert.notNull(jtaTransactionManager, "Transaction manager reference must not be null");
if (jtaTransactionManager instanceof JtaTransactionManager) {
boolean webspherePresent = ClassUtils.isPresent("com.ibm.wsspi.uow.UOWManager", getClass().getClassLoader());
if (webspherePresent) {
getProperties().put(AvailableSettings.JTA_PLATFORM, new WebSphereExtendedJtaPlatform());
}
else {
JtaTransactionManager jtaTm = (JtaTransactionManager) jtaTransactionManager;
if (jtaTm.getTransactionManager() == null) {
throw new IllegalArgumentException(
"Can only apply JtaTransactionManager which has a TransactionManager reference set");
}
getProperties().put(AvailableSettings.JTA_PLATFORM,
new ConfigurableJtaPlatform(jtaTm.getTransactionManager(), jtaTm.getUserTransaction()));
}
}
else if (jtaTransactionManager instanceof TransactionManager) {
getProperties().put(AvailableSettings.JTA_PLATFORM,
new ConfigurableJtaPlatform((TransactionManager) jtaTransactionManager, null));
}
else {
throw new IllegalArgumentException(
"Unknown transaction manager type: " + jtaTransactionManager.getClass().getName());
}
getProperties().put(AvailableSettings.TRANSACTION_STRATEGY, new CMTTransactionFactory());
return this;
}
/**
* Add the given annotated classes in a batch.
* @see #addAnnotatedClass
* @see #scanPackages
*/
public LocalSessionFactoryBuilder addAnnotatedClasses(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
ReflectionUtils.invokeMethod(addAnnotatedClassMethod, this, annotatedClass);
}
return this;
}
/**
* Add the given annotated packages in a batch.
* @see #addPackage
* @see #scanPackages
*/
public LocalSessionFactoryBuilder addPackages(String... annotatedPackages) {
for (String annotatedPackage :annotatedPackages) {
ReflectionUtils.invokeMethod(addPackageMethod, this, annotatedPackage);
}
return this;
}
/**
* Perform Spring-based scanning for entity classes, registering them
* as annotated classes with this {@code Configuration}.
* @param packagesToScan one or more Java package names
* @throws HibernateException if scanning fails for any reason
*/
public LocalSessionFactoryBuilder scanPackages(String... packagesToScan) throws HibernateException {
try {
for (String pkg : 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)) {
addAnnotatedClasses(this.resourcePatternResolver.getClassLoader().loadClass(className));
}
}
}
}
return this;
}
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 {
for (TypeFilter filter : ENTITY_TYPE_FILTERS) {
if (filter.match(reader, readerFactory)) {
return true;
}
}
return false;
}
/**
* Build the {@code SessionFactory}.
*/
@Override
@SuppressWarnings("deprecation")
public SessionFactory buildSessionFactory() throws HibernateException {
ClassLoader appClassLoader = (ClassLoader) getProperties().get(AvailableSettings.APP_CLASSLOADER);
Thread currentThread = Thread.currentThread();
ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
boolean overrideClassLoader =
(appClassLoader != null && !appClassLoader.equals(threadContextClassLoader));
if (overrideClassLoader) {
currentThread.setContextClassLoader(appClassLoader);
}
try {
return super.buildSessionFactory();
}
finally {
if (overrideClassLoader) {
currentThread.setContextClassLoader(threadContextClassLoader);
}
}
}
}

View File

@@ -1,209 +0,0 @@
/*
* Copyright 2002-2012 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.hibernate4;
import java.lang.reflect.Method;
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.NonUniqueObjectException;
import org.hibernate.NonUniqueResultException;
import org.hibernate.ObjectDeletedException;
import org.hibernate.PersistentObjectException;
import org.hibernate.PropertyValueException;
import org.hibernate.QueryException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StaleObjectStateException;
import org.hibernate.StaleStateException;
import org.hibernate.TransientObjectException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.WrongClassException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.DataException;
import org.hibernate.exception.JDBCConnectionException;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.SQLGrammarException;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* Helper class featuring methods for Hibernate Session handling.
* Also provides support for exception translation.
*
* <p>Used internally by {@link HibernateTransactionManager}.
* Can also be used directly in application code.
*
* @author Juergen Hoeller
* @since 3.1
* @see HibernateExceptionTranslator
* @see HibernateTransactionManager
*/
public abstract class SessionFactoryUtils {
/**
* Order value for TransactionSynchronization objects that clean up Hibernate Sessions.
* Returns <code>DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100</code>
* to execute Session cleanup before JDBC Connection cleanup, if any.
* @see org.springframework.jdbc.datasource.DataSourceUtils#CONNECTION_SYNCHRONIZATION_ORDER
*/
public static final int SESSION_SYNCHRONIZATION_ORDER =
DataSourceUtils.CONNECTION_SYNCHRONIZATION_ORDER - 100;
/**
* A Method handle for the <code>SessionFactory.openSession()</code> method.
* The return value differs between Hibernate 3.x and 4.x; for cross-compilation purposes,
* we have to use reflection here as long as we keep compiling against Hibernate 3.x jars.
*/
private static final Method openSessionMethod = ClassUtils.getMethod(SessionFactory.class, "openSession");
static final Log logger = LogFactory.getLog(SessionFactoryUtils.class);
/**
* Determine the DataSource of the given SessionFactory.
* @param sessionFactory the SessionFactory to check
* @return the DataSource, or <code>null</code> if none found
* @see org.hibernate.engine.spi.SessionFactoryImplementor#getConnectionProvider
*/
public static DataSource getDataSource(SessionFactory sessionFactory) {
if (sessionFactory instanceof SessionFactoryImplementor) {
ConnectionProvider cp = ((SessionFactoryImplementor) sessionFactory).getConnectionProvider();
return cp.unwrap(DataSource.class);
}
return null;
}
/**
* Obtain a new Session from the given SessionFactory.
* <p>Bridges between Hibernate signature differences.
* @param sessionFactory the SessionFactory to use
* @return the new Session
* @see org.hibernate.SessionFactory#openSession()
*/
public static Session openSession(SessionFactory sessionFactory) {
return (Session) ReflectionUtils.invokeMethod(openSessionMethod, sessionFactory);
}
/**
* Perform actual closing of the Hibernate Session,
* catching and logging any cleanup exceptions thrown.
* @param session the Hibernate Session to close (may be <code>null</code>)
* @see org.hibernate.Session#close()
*/
public static void closeSession(Session session) {
if (session != null) {
try {
session.close();
}
catch (HibernateException ex) {
logger.debug("Could not close Hibernate Session", ex);
}
catch (Throwable ex) {
logger.debug("Unexpected exception on closing Hibernate Session", ex);
}
}
}
/**
* Convert the given HibernateException to an appropriate exception
* from the <code>org.springframework.dao</code> hierarchy.
* @param ex HibernateException that occured
* @return the corresponding DataAccessException instance
* @see HibernateExceptionTranslator#convertHibernateAccessException
* @see HibernateTransactionManager#convertHibernateAccessException
*/
public static DataAccessException convertHibernateAccessException(HibernateException ex) {
if (ex instanceof JDBCConnectionException) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
}
if (ex instanceof SQLGrammarException) {
SQLGrammarException jdbcEx = (SQLGrammarException) ex;
return new InvalidDataAccessResourceUsageException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof LockAcquisitionException) {
LockAcquisitionException jdbcEx = (LockAcquisitionException) ex;
return new CannotAcquireLockException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof ConstraintViolationException) {
ConstraintViolationException jdbcEx = (ConstraintViolationException) ex;
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() +
"]; constraint [" + jdbcEx.getConstraintName() + "]", ex);
}
if (ex instanceof DataException) {
DataException jdbcEx = (DataException) ex;
return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex);
}
if (ex instanceof JDBCException) {
return new HibernateJdbcException((JDBCException) ex);
}
// end of JDBCException (subclass) handling
if (ex instanceof QueryException) {
return new HibernateQueryException((QueryException) ex);
}
if (ex instanceof NonUniqueResultException) {
return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex);
}
if (ex instanceof NonUniqueObjectException) {
return new DuplicateKeyException(ex.getMessage(), ex);
}
if (ex instanceof PropertyValueException) {
return new DataIntegrityViolationException(ex.getMessage(), ex);
}
if (ex instanceof PersistentObjectException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof TransientObjectException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof ObjectDeletedException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
if (ex instanceof UnresolvableObjectException) {
return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex);
}
if (ex instanceof WrongClassException) {
return new HibernateObjectRetrievalFailureException((WrongClassException) ex);
}
if (ex instanceof StaleObjectStateException) {
return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex);
}
if (ex instanceof StaleStateException) {
return new HibernateOptimisticLockingFailureException((StaleStateException) ex);
}
// fallback
return new HibernateSystemException(ex);
}
}

View File

@@ -1,80 +0,0 @@
/*
* 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.hibernate4;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.util.Assert;
/**
* Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
* HibernateTransactionManager binds instances of this class to the thread,
* for a given SessionFactory.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
* @author Juergen Hoeller
* @since 3.1
* @see HibernateTransactionManager
* @see SessionFactoryUtils
*/
public class SessionHolder extends ResourceHolderSupport {
private Session session;
private Transaction transaction;
private FlushMode previousFlushMode;
public SessionHolder(Session session) {
Assert.notNull(session, "Session must not be null");
this.session = session;
}
public Session getSession() {
return this.session;
}
public void setTransaction(Transaction transaction) {
this.transaction = transaction;
}
public Transaction getTransaction() {
return this.transaction;
}
public void setPreviousFlushMode(FlushMode previousFlushMode) {
this.previousFlushMode = previousFlushMode;
}
public FlushMode getPreviousFlushMode() {
return this.previousFlushMode;
}
@Override
public void clear() {
super.clear();
this.transaction = null;
this.previousFlushMode = null;
}
}

View File

@@ -1,64 +0,0 @@
/*
* 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.hibernate4;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
/**
* Simple synchronization adapter that propagates a <code>flush()</code> call
* to the underlying Hibernate Session. Used in combination with JTA.
*
* @author Juergen Hoeller
* @since 3.1
*/
class SpringFlushSynchronization extends TransactionSynchronizationAdapter {
private final Session session;
public SpringFlushSynchronization(Session session) {
this.session = session;
}
@Override
public void flush() {
try {
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
this.session.flush();
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
@Override
public boolean equals(Object obj) {
return (obj instanceof SpringFlushSynchronization &&
this.session == ((SpringFlushSynchronization) obj).session);
}
@Override
public int hashCode() {
return this.session.hashCode();
}
}

View File

@@ -1,48 +0,0 @@
/*
* 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.hibernate4;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.context.internal.JTASessionContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Spring-specific subclass of Hibernate's JTASessionContext,
* setting <code>FlushMode.MANUAL</code> for read-only transactions.
*
* @author Juergen Hoeller
* @since 3.1
*/
public class SpringJtaSessionContext extends JTASessionContext {
public SpringJtaSessionContext(SessionFactoryImplementor factory) {
super(factory);
}
@Override
protected Session buildOrObtainSession() {
Session session = super.buildOrObtainSession();
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.MANUAL);
}
return session;
}
}

View File

@@ -1,101 +0,0 @@
/*
* 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.hibernate4;
import javax.transaction.TransactionManager;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.context.spi.CurrentSessionContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Implementation of Hibernate 3.1's CurrentSessionContext interface
* that delegates to Spring's SessionFactoryUtils for providing a
* Spring-managed current Session.
*
* <p>This CurrentSessionContext implementation can also be specified in custom
* SessionFactory setup through the "hibernate.current_session_context_class"
* property, with the fully qualified name of this class as value.
*
* @author Juergen Hoeller
* @since 3.1
*/
@SuppressWarnings("serial")
public class SpringSessionContext implements CurrentSessionContext {
private final SessionFactoryImplementor sessionFactory;
private final CurrentSessionContext jtaSessionContext;
/**
* Create a new SpringSessionContext for the given Hibernate SessionFactory.
* @param sessionFactory the SessionFactory to provide current Sessions for
*/
public SpringSessionContext(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
JtaPlatform jtaPlatform = sessionFactory.getServiceRegistry().getService(JtaPlatform.class);
TransactionManager transactionManager = jtaPlatform.retrieveTransactionManager();
this.jtaSessionContext = (transactionManager != null ? new SpringJtaSessionContext(sessionFactory) : null);
}
/**
* Retrieve the Spring-managed Session for the current thread, if any.
*/
public Session currentSession() throws HibernateException {
Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
if (value instanceof Session) {
return (Session) value;
}
else if (value instanceof SessionHolder) {
SessionHolder sessionHolder = (SessionHolder) value;
Session session = sessionHolder.getSession();
if (TransactionSynchronizationManager.isSynchronizationActive() &&
!sessionHolder.isSynchronizedWithTransaction()) {
TransactionSynchronizationManager.registerSynchronization(
new SpringSessionSynchronization(sessionHolder, this.sessionFactory));
sessionHolder.setSynchronizedWithTransaction(true);
// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
FlushMode flushMode = session.getFlushMode();
if (FlushMode.isManualFlushMode(flushMode) &&
!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
session.setFlushMode(FlushMode.AUTO);
sessionHolder.setPreviousFlushMode(flushMode);
}
}
return session;
}
else if (this.jtaSessionContext != null) {
Session session = this.jtaSessionContext.currentSession();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new SpringFlushSynchronization(session));
}
return session;
}
else {
throw new HibernateException("No Session found for current thread");
}
}
}

View File

@@ -1,126 +0,0 @@
/*
* 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.hibernate4;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.core.Ordered;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Callback for resource cleanup at the end of a Spring-managed transaction
* for a pre-bound Hibernate Session.
*
* @author Juergen Hoeller
* @since 3.1
*/
class SpringSessionSynchronization implements TransactionSynchronization, Ordered {
private final SessionHolder sessionHolder;
private final SessionFactory sessionFactory;
private boolean holderActive = true;
public SpringSessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory) {
this.sessionHolder = sessionHolder;
this.sessionFactory = sessionFactory;
}
private Session getCurrentSession() {
return this.sessionHolder.getSession();
}
public int getOrder() {
return SessionFactoryUtils.SESSION_SYNCHRONIZATION_ORDER;
}
public void suspend() {
if (this.holderActive) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
// Eagerly disconnect the Session here, to make release mode "on_close" work on JBoss.
getCurrentSession().disconnect();
}
}
public void resume() {
if (this.holderActive) {
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
}
}
public void flush() {
try {
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on explicit request");
getCurrentSession().flush();
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
public void beforeCommit(boolean readOnly) throws DataAccessException {
if (!readOnly) {
Session session = getCurrentSession();
// Read-write transaction -> flush the Hibernate Session.
// Further check: only flush when not FlushMode.MANUAL.
if (!FlushMode.isManualFlushMode(session.getFlushMode())) {
try {
SessionFactoryUtils.logger.debug("Flushing Hibernate Session on transaction synchronization");
session.flush();
}
catch (HibernateException ex) {
throw SessionFactoryUtils.convertHibernateAccessException(ex);
}
}
}
}
public void beforeCompletion() {
Session session = this.sessionHolder.getSession();
if (this.sessionHolder.getPreviousFlushMode() != null) {
// In case of pre-bound Session, restore previous flush mode.
session.setFlushMode(this.sessionHolder.getPreviousFlushMode());
}
// Eagerly disconnect the Session here, to make release mode "on_close" work nicely.
session.disconnect();
}
public void afterCommit() {
}
public void afterCompletion(int status) {
try {
if (status != STATUS_COMMITTED) {
// Clear all pending inserts/updates/deletes in the Session.
// Necessary for pre-bound Sessions, to avoid inconsistent state.
this.sessionHolder.getSession().clear();
}
}
finally {
this.sessionHolder.setSynchronizedWithTransaction(false);
}
}
}

View File

@@ -1,17 +0,0 @@
/**
*
* Package providing integration of
* <a href="http://www.hibernate.org">Hibernate 4.x</a>
* with Spring concepts.
*
* <p>Contains an implementation of Spring's transaction SPI for local Hibernate transactions.
* This package is intentionally rather minimal, with no template classes or the like,
* in order to follow native Hibernate recommendations as closely as possible.
*
* <p><b>This package supports Hibernate 4.x only.</b>
* See the <code>org.springframework.orm.hibernate3</code> package for Hibernate 3.x support.
*
*/
package org.springframework.orm.hibernate4;

View File

@@ -1,252 +0,0 @@
/*
* Copyright 2002-2012 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.hibernate4.support;
import java.io.IOException;
import java.util.concurrent.Callable;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate4.SessionFactoryUtils;
import org.springframework.orm.hibernate4.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Servlet 2.3 Filter that binds a Hibernate Session to the thread for the entire
* processing of the request. Intended for the "Open Session in View" pattern,
* i.e. to allow for lazy loading in web views despite the original transactions
* already being completed.
*
* <p>This filter makes Hibernate Sessions available via the current thread, which
* will be autodetected by transaction managers. It is suitable for service layer
* transactions via {@link org.springframework.orm.hibernate4.HibernateTransactionManager}
* as well as for non-transactional execution (if configured appropriately).
*
* <p><b>NOTE</b>: This filter will by default <i>not</i> flush the Hibernate Session,
* with the flush mode set to <code>FlushMode.NEVER</code>. It assumes to be used
* in combination with service layer transactions that care for the flushing: The
* active transaction manager will temporarily change the flush mode to
* <code>FlushMode.AUTO</code> during a read-write transaction, with the flush
* mode reset to <code>FlushMode.NEVER</code> at the end of each transaction.
*
* <p><b>WARNING:</b> Applying this filter to existing logic can cause issues that
* have not appeared before, through the use of a single Hibernate Session for the
* processing of an entire request. In particular, the reassociation of persistent
* objects with a Hibernate Session has to occur at the very beginning of request
* processing, to avoid clashes with already loaded instances of the same objects.
*
* <p>Looks up the SessionFactory in Spring's root web application context.
* Supports a "sessionFactoryBeanName" filter init-param in <code>web.xml</code>;
* the default bean name is "sessionFactory". Looks up the SessionFactory on each
* request, to avoid initialization order issues (when using ContextLoaderServlet,
* the root application context will get initialized <i>after</i> this filter).
*
* @author Juergen Hoeller
* @since 3.1
* @see #lookupSessionFactory
* @see OpenSessionInViewInterceptor
* @see org.springframework.orm.hibernate4.HibernateTransactionManager
* @see org.springframework.transaction.support.TransactionSynchronizationManager
*/
public class OpenSessionInViewFilter extends OncePerRequestFilter {
public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";
private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;
/**
* Set the bean name of the SessionFactory to fetch from Spring's
* root application context. Default is "sessionFactory".
* @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
*/
public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
this.sessionFactoryBeanName = sessionFactoryBeanName;
}
/**
* Return the bean name of the SessionFactory to fetch from Spring's
* root application context.
*/
protected String getSessionFactoryBeanName() {
return this.sessionFactoryBeanName;
}
/**
* Returns "false" so that the filter may re-bind the opened Hibernate
* {@code Session} to each asynchronously dispatched thread and postpone
* closing it until the very last asynchronous dispatch.
*/
@Override
protected boolean shouldNotFilterAsyncDispatch() {
return false;
}
/**
* Returns "false" so that the filter may provide a Hibernate
* {@code Session} to each error dispatches.
*/
@Override
protected boolean shouldNotFilterErrorDispatch() {
return false;
}
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
SessionFactory sessionFactory = lookupSessionFactory(request);
boolean participate = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
String key = getAlreadyFilteredAttributeName();
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
// Do not modify the Session: just set the participate flag.
participate = true;
}
else {
boolean isFirstRequest = !isAsyncDispatch(request);
if (isFirstRequest || !applySessionBindingInterceptor(asyncManager, key)) {
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
Session session = openSession(sessionFactory);
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
asyncManager.registerCallableInterceptor(key,
new SessionBindingCallableInterceptor(sessionFactory, sessionHolder));
}
}
try {
filterChain.doFilter(request, response);
}
finally {
if (!participate) {
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
if (!isAsyncStarted(request)) {
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
}
}
/**
* Look up the SessionFactory that this filter should use,
* taking the current HTTP request as argument.
* <p>The default implementation delegates to the {@link #lookupSessionFactory()}
* variant without arguments.
* @param request the current request
* @return the SessionFactory to use
*/
protected SessionFactory lookupSessionFactory(HttpServletRequest request) {
return lookupSessionFactory();
}
/**
* Look up the SessionFactory that this filter should use.
* <p>The default implementation looks for a bean with the specified name
* in Spring's root application context.
* @return the SessionFactory to use
* @see #getSessionFactoryBeanName
*/
protected SessionFactory lookupSessionFactory() {
if (logger.isDebugEnabled()) {
logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
}
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
}
/**
* Open a Session for the SessionFactory that this filter uses.
* <p>The default implementation delegates to the
* <code>SessionFactory.openSession</code> method and
* sets the <code>Session</code>'s flush mode to "MANUAL".
* @param sessionFactory the SessionFactory that this filter uses
* @return the Session to use
* @throws DataAccessResourceFailureException if the Session could not be created
* @see org.hibernate.FlushMode#MANUAL
*/
protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
try {
Session session = SessionFactoryUtils.openSession(sessionFactory);
session.setFlushMode(FlushMode.MANUAL);
return session;
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
}
}
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((SessionBindingCallableInterceptor) asyncManager.getCallableInterceptor(key)).initializeThread();
return true;
}
/**
* Bind and unbind the Hibernate {@code Session} to the current thread.
*/
private static class SessionBindingCallableInterceptor extends CallableProcessingInterceptorAdapter {
private final SessionFactory sessionFactory;
private final SessionHolder sessionHolder;
public SessionBindingCallableInterceptor(SessionFactory sessionFactory, SessionHolder sessionHolder) {
this.sessionFactory = sessionFactory;
this.sessionHolder = sessionHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
initializeThread();
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}
private void initializeThread() {
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
}
}
}

View File

@@ -1,241 +0,0 @@
/*
* Copyright 2002-2012 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.hibernate4.support;
import java.util.concurrent.Callable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate4.SessionFactoryUtils;
import org.springframework.orm.hibernate4.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.AsyncWebRequestInterceptor;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
/**
* Spring web request interceptor that binds a Hibernate <code>Session</code> to the
* thread for the entire processing of the request.
*
* <p>This class is a concrete expression of the "Open Session in View" pattern, which
* is a pattern that allows for the lazy loading of associations in web views despite
* the original transactions already being completed.
*
* <p>This interceptor makes Hibernate Sessions available via the current thread,
* which will be autodetected by transaction managers. It is suitable for service layer
* transactions via {@link org.springframework.orm.hibernate4.HibernateTransactionManager}
* as well as for non-transactional execution (if configured appropriately).
*
* <p><b>NOTE</b>: This interceptor will by default <i>not</i> flush the Hibernate
* <code>Session</code>, with the flush mode being set to <code>FlushMode.NEVER</code>.
* It assumes that it will be used in combination with service layer transactions
* that handle the flushing: the active transaction manager will temporarily change
* the flush mode to <code>FlushMode.AUTO</code> during a read-write transaction,
* with the flush mode reset to <code>FlushMode.NEVER</code> at the end of each
* transaction. If you intend to use this interceptor without transactions, consider
* changing the default flush mode (through the {@link #setFlushMode "flushMode"} property).
*
* <p>In contrast to {@link OpenSessionInViewFilter}, this interceptor is configured
* in a Spring application context and can thus take advantage of bean wiring..
*
* <p><b>WARNING:</b> Applying this interceptor to existing logic can cause issues
* that have not appeared before, through the use of a single Hibernate
* <code>Session</code> for the processing of an entire request. In particular, the
* reassociation of persistent objects with a Hibernate <code>Session</code> has to
* occur at the very beginning of request processing, to avoid clashes with already
* loaded instances of the same objects.
*
* @author Juergen Hoeller
* @since 3.1
* @see #setSingleSession
* @see #setFlushMode
* @see OpenSessionInViewFilter
* @see org.springframework.orm.hibernate4.HibernateTransactionManager
* @see org.springframework.transaction.support.TransactionSynchronizationManager
*/
public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor {
/**
* Suffix that gets appended to the <code>SessionFactory</code>
* <code>toString()</code> representation for the "participate in existing
* session handling" request attribute.
* @see #getParticipateAttributeName
*/
public static final String PARTICIPATE_SUFFIX = ".PARTICIPATE";
protected final Log logger = LogFactory.getLog(getClass());
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
/**
* Open a new Hibernate <code>Session</code> according to the settings of this
* <code>HibernateAccessor</code> and bind it to the thread via the
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}.
*/
public void preHandle(WebRequest request) throws DataAccessException {
String participateAttributeName = getParticipateAttributeName();
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
if (asyncManager.hasConcurrentResult()) {
if (applySessionBindingInterceptor(asyncManager, participateAttributeName)) {
return;
}
}
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
// Do not modify the Session: just mark the request accordingly.
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
int newCount = (count != null ? count + 1 : 1);
request.setAttribute(getParticipateAttributeName(), newCount, WebRequest.SCOPE_REQUEST);
}
else {
logger.debug("Opening Hibernate Session in OpenSessionInViewInterceptor");
Session session = openSession();
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
asyncManager.registerCallableInterceptor(participateAttributeName,
new SessionBindingCallableInterceptor(sessionHolder));
}
}
public void postHandle(WebRequest request, ModelMap model) {
}
/**
* Unbind the Hibernate <code>Session</code> from the thread and close it).
* @see org.springframework.transaction.support.TransactionSynchronizationManager
*/
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
if (!decrementParticipateCount(request)) {
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
logger.debug("Closing Hibernate Session in OpenSessionInViewInterceptor");
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
private boolean decrementParticipateCount(WebRequest request) {
String participateAttributeName = getParticipateAttributeName();
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
if (count == null) {
return false;
}
// Do not modify the Session: just clear the marker.
if (count > 1) {
request.setAttribute(participateAttributeName, count - 1, WebRequest.SCOPE_REQUEST);
}
else {
request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
}
return true;
}
public void afterConcurrentHandlingStarted(WebRequest request) {
if (!decrementParticipateCount(request)) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
}
/**
* Open a Session for the SessionFactory that this interceptor uses.
* <p>The default implementation delegates to the
* <code>SessionFactory.openSession</code> method and
* sets the <code>Session</code>'s flush mode to "MANUAL".
* @return the Session to use
* @throws DataAccessResourceFailureException if the Session could not be created
* @see org.hibernate.FlushMode#MANUAL
*/
protected Session openSession() throws DataAccessResourceFailureException {
try {
Session session = SessionFactoryUtils.openSession(getSessionFactory());
session.setFlushMode(FlushMode.MANUAL);
return session;
}
catch (HibernateException ex) {
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
}
}
/**
* Return the name of the request attribute that identifies that a request is
* already intercepted.
* <p>The default implementation takes the <code>toString()</code> representation
* of the <code>SessionFactory</code> instance and appends {@link #PARTICIPATE_SUFFIX}.
*/
protected String getParticipateAttributeName() {
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
}
private boolean applySessionBindingInterceptor(WebAsyncManager asyncManager, String key) {
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((SessionBindingCallableInterceptor) asyncManager.getCallableInterceptor(key)).initializeThread();
return true;
}
/**
* Bind and unbind the Hibernate {@code Session} to the current thread.
*/
private class SessionBindingCallableInterceptor extends CallableProcessingInterceptorAdapter {
private final SessionHolder sessionHolder;
public SessionBindingCallableInterceptor(SessionHolder sessionHolder) {
this.sessionHolder = sessionHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
initializeThread();
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
private void initializeThread() {
TransactionSynchronizationManager.bindResource(getSessionFactory(), this.sessionHolder);
}
}
}

View File

@@ -1,24 +0,0 @@
/*
* 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.
*/
/**
*
* Classes supporting the <code>org.springframework.orm.hibernate4</code> package.
*
*/
package org.springframework.orm.hibernate4.support;