18 changed files with 2197 additions and 0 deletions
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
/* |
||||
* 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 org.springframework.dao.DataAccessException} hierarchy. |
||||
* |
||||
* @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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
/* |
||||
* 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(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
/* |
||||
* 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(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
/* |
||||
* 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); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,696 @@
@@ -0,0 +1,696 @@
|
||||
/* |
||||
* 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.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; |
||||
|
||||
/** |
||||
* {@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 { |
||||
|
||||
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 = getSessionFactory().getCurrentSession(); |
||||
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 = getSessionFactory().openSession(); |
||||
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; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,229 @@
@@ -0,0 +1,229 @@
|
||||
/* |
||||
* 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.io.IOException; |
||||
import java.lang.reflect.Method; |
||||
import java.util.Properties; |
||||
import javax.persistence.Embeddable; |
||||
import javax.persistence.Entity; |
||||
import javax.persistence.MappedSuperclass; |
||||
import javax.sql.DataSource; |
||||
|
||||
import org.hibernate.MappingException; |
||||
import org.hibernate.SessionFactory; |
||||
import org.hibernate.cfg.Configuration; |
||||
import org.hibernate.cfg.Environment; |
||||
|
||||
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.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.util.ClassUtils; |
||||
import org.springframework.util.ReflectionUtils; |
||||
|
||||
/** |
||||
* {@link org.springframework.beans.factory.FactoryBean} that creates a |
||||
* Hibernate {@link org.hibernate.SessionFactory}. This is the usual way to |
||||
* set up a shared Hibernate SessionFactory in a Spring application context; |
||||
* the SessionFactory can then be passed to Hibernate-based DAOs via |
||||
* dependency injection. |
||||
* |
||||
* <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. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 3.1 |
||||
* @see #setDataSource |
||||
* @see #setPackagesToScan |
||||
*/ |
||||
public class LocalSessionFactoryBean implements FactoryBean<SessionFactory>, ResourceLoaderAware, |
||||
InitializingBean, DisposableBean { |
||||
|
||||
private static final String RESOURCE_PATTERN = "/**/*.class"; |
||||
|
||||
private static final Method addAnnotatedClassMethod = |
||||
ClassUtils.getMethodIfAvailable(Configuration.class, "addAnnotatedClass", Class.class); |
||||
|
||||
|
||||
private DataSource dataSource; |
||||
|
||||
private Properties hibernateProperties; |
||||
|
||||
private String[] packagesToScan; |
||||
|
||||
private Class<?>[] annotatedClasses; |
||||
|
||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); |
||||
|
||||
private TypeFilter[] entityTypeFilters = new TypeFilter[] { |
||||
new AnnotationTypeFilter(Entity.class, false), |
||||
new AnnotationTypeFilter(Embeddable.class, false), |
||||
new AnnotationTypeFilter(MappedSuperclass.class, false)}; |
||||
|
||||
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. |
||||
* <p>If using HibernateTransactionManager as transaction strategy, consider |
||||
* proxying your target DataSource with a LazyConnectionDataSourceProxy. |
||||
* This defers fetching of an actual JDBC Connection until the first JDBC |
||||
* Statement gets executed, even within JDBC transactions (as performed by |
||||
* HibernateTransactionManager). Such lazy fetching is particularly beneficial |
||||
* for read-only operations, in particular if the chances of resolving the |
||||
* result in the second-level cache are high. |
||||
* <p>As JTA and transactional JNDI DataSources already provide lazy enlistment |
||||
* of JDBC Connections, LazyConnectionDataSourceProxy does not add value with |
||||
* JTA (i.e. Spring's JtaTransactionManager) as transaction strategy. |
||||
* @see HibernateTransactionManager |
||||
* @see org.springframework.transaction.jta.JtaTransactionManager |
||||
* @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy |
||||
*/ |
||||
public void setDataSource(DataSource dataSource) { |
||||
this.dataSource = dataSource; |
||||
} |
||||
|
||||
/** |
||||
* Set Hibernate properties, such as "hibernate.dialect". |
||||
* <p>Can be used to override values in a Hibernate XML config file, |
||||
* or to specify all necessary properties locally. |
||||
* <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; |
||||
} |
||||
|
||||
/** |
||||
* 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; |
||||
} |
||||
|
||||
/** |
||||
* Specify annotated entity classes to register with this Hibernate SessionFactory. |
||||
*/ |
||||
public void setAnnotatedClasses(Class<?>... annotatedClasses) { |
||||
this.annotatedClasses = annotatedClasses; |
||||
} |
||||
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) { |
||||
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); |
||||
} |
||||
|
||||
|
||||
public void afterPropertiesSet() { |
||||
Configuration config = new Configuration(); |
||||
config.getProperties().put(Environment.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName()); |
||||
config.getProperties().put(Environment.DATASOURCE, this.dataSource); |
||||
config.getProperties().put("hibernate.classLoader.application", this.resourcePatternResolver.getClassLoader()); |
||||
config.addProperties(this.hibernateProperties); |
||||
scanPackages(config); |
||||
for (Class<?> annotatedClass : this.annotatedClasses) { |
||||
ReflectionUtils.invokeMethod(addAnnotatedClassMethod, config, annotatedClass); |
||||
} |
||||
this.sessionFactory = config.buildSessionFactory(); |
||||
} |
||||
|
||||
/** |
||||
* Perform Spring-based scanning for entity classes. |
||||
* @see #setPackagesToScan |
||||
*/ |
||||
private void scanPackages(Configuration config) { |
||||
if (this.packagesToScan != null) { |
||||
try { |
||||
for (String pkg : this.packagesToScan) { |
||||
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + |
||||
ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN; |
||||
Resource[] resources = this.resourcePatternResolver.getResources(pattern); |
||||
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); |
||||
for (Resource resource : resources) { |
||||
if (resource.isReadable()) { |
||||
MetadataReader reader = readerFactory.getMetadataReader(resource); |
||||
String className = reader.getClassMetadata().getClassName(); |
||||
if (matchesFilter(reader, readerFactory)) { |
||||
Class<?> annotatedClass = this.resourcePatternResolver.getClassLoader().loadClass(className); |
||||
ReflectionUtils.invokeMethod(addAnnotatedClassMethod, config, annotatedClass); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
catch (IOException ex) { |
||||
throw new MappingException("Failed to scan classpath for unlisted classes", ex); |
||||
} |
||||
catch (ClassNotFoundException ex) { |
||||
throw new MappingException("Failed to load annotated classes from classpath", ex); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Check whether any of the configured entity type filters matches |
||||
* the current class descriptor contained in the metadata reader. |
||||
*/ |
||||
private boolean matchesFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException { |
||||
if (this.entityTypeFilters != null) { |
||||
for (TypeFilter filter : this.entityTypeFilters) { |
||||
if (filter.match(reader, readerFactory)) { |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
|
||||
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(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,181 @@
@@ -0,0 +1,181 @@
|
||||
/* |
||||
* 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.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.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.IncorrectResultSizeDataAccessException; |
||||
import org.springframework.dao.InvalidDataAccessApiUsageException; |
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException; |
||||
import org.springframework.jdbc.datasource.DataSourceUtils; |
||||
|
||||
/** |
||||
* 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; |
||||
|
||||
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; |
||||
} |
||||
|
||||
/** |
||||
* 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); |
||||
} |
||||
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 QueryException) { |
||||
return new HibernateQueryException((QueryException) ex); |
||||
} |
||||
if (ex instanceof UnresolvableObjectException) { |
||||
return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex); |
||||
} |
||||
if (ex instanceof WrongClassException) { |
||||
return new HibernateObjectRetrievalFailureException((WrongClassException) ex); |
||||
} |
||||
if (ex instanceof NonUniqueResultException) { |
||||
return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex); |
||||
} |
||||
if (ex instanceof StaleObjectStateException) { |
||||
return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex); |
||||
} |
||||
if (ex instanceof StaleStateException) { |
||||
return new HibernateOptimisticLockingFailureException((StaleStateException) ex); |
||||
} |
||||
|
||||
// fallback
|
||||
return new HibernateSystemException(ex); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
/* |
||||
* 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.session = null; |
||||
this.transaction = null; |
||||
this.previousFlushMode = null; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
/* |
||||
* 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(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
/* |
||||
* 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; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
/* |
||||
* Copyright 2002-2011 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.orm.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"); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,122 @@
@@ -0,0 +1,122 @@
|
||||
/* |
||||
* 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) { |
||||
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(); |
||||
} |
||||
this.sessionHolder.setSynchronizedWithTransaction(false); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
|
||||
/** |
||||
* |
||||
* Package providing integration of |
||||
* <a href="http://www.hibernate.org">Hibernate 4.0</a> |
||||
* with Spring concepts. |
||||
* |
||||
* <p>Contains an implementation of Spring's transaction SPI for local Hibernate transactions. |
||||
* This package is intentionally rather minimal, relying on native Hibernate builder APIs |
||||
* for building a SessionFactory (for example in an @Bean method in a @Configuration class). |
||||
* |
||||
* <p><b>This package supports Hibernate 4.x only.</b> |
||||
* See the org.springframework.orm.hibernate3 package for Hibernate 3.x support. |
||||
* |
||||
*/ |
||||
package org.springframework.orm.hibernate4; |
||||
|
||||
@ -0,0 +1,180 @@
@@ -0,0 +1,180 @@
|
||||
/* |
||||
* 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.support; |
||||
|
||||
import java.io.IOException; |
||||
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.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; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected void doFilterInternal( |
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) |
||||
throws ServletException, IOException { |
||||
|
||||
SessionFactory sessionFactory = lookupSessionFactory(request); |
||||
boolean participate = false; |
||||
|
||||
if (TransactionSynchronizationManager.hasResource(sessionFactory)) { |
||||
// Do not modify the Session: just set the participate flag.
|
||||
participate = true; |
||||
} |
||||
else { |
||||
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter"); |
||||
Session session = openSession(sessionFactory); |
||||
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session)); |
||||
} |
||||
|
||||
try { |
||||
filterChain.doFilter(request, response); |
||||
} |
||||
|
||||
finally { |
||||
if (!participate) { |
||||
SessionHolder sessionHolder = |
||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory); |
||||
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 = sessionFactory.openSession(); |
||||
session.setFlushMode(FlushMode.MANUAL); |
||||
return session; |
||||
} |
||||
catch (HibernateException ex) { |
||||
throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,176 @@
@@ -0,0 +1,176 @@
|
||||
/* |
||||
* 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.support; |
||||
|
||||
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.WebRequest; |
||||
import org.springframework.web.context.request.WebRequestInterceptor; |
||||
|
||||
/** |
||||
* 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 WebRequestInterceptor { |
||||
|
||||
/** |
||||
* 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 { |
||||
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) { |
||||
// Do not modify the Session: just mark the request accordingly.
|
||||
String participateAttributeName = getParticipateAttributeName(); |
||||
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(); |
||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session)); |
||||
} |
||||
} |
||||
|
||||
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 { |
||||
String participateAttributeName = getParticipateAttributeName(); |
||||
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST); |
||||
if (count != null) { |
||||
// 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); |
||||
} |
||||
} |
||||
else { |
||||
SessionHolder sessionHolder = |
||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory()); |
||||
logger.debug("Closing Hibernate Session in OpenSessionInViewInterceptor"); |
||||
SessionFactoryUtils.closeSession(sessionHolder.getSession()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 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 = getSessionFactory().openSession(); |
||||
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; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
|
||||
/* |
||||
* 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; |
||||
|
||||
Loading…
Reference in new issue