org.springframework.orm.toplink.SessionFactoryUtils Maven / Gradle / Ivy
/*
* Copyright 2002-2006 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.toplink;
import oracle.toplink.exceptions.ConcurrencyException;
import oracle.toplink.exceptions.ConversionException;
import oracle.toplink.exceptions.DatabaseException;
import oracle.toplink.exceptions.OptimisticLockException;
import oracle.toplink.exceptions.QueryException;
import oracle.toplink.exceptions.TopLinkException;
import oracle.toplink.sessions.Session;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.TypeMismatchDataAccessException;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
/**
* Helper class featuring methods for TopLink Session handling,
* allowing for reuse of TopLink Session instances within transactions.
* Also provides support for exception translation.
*
* Mainly intended for internal use within the framework.
*
* @author Juergen Hoeller
* @author James Clark
* @since 1.2
*/
public abstract class SessionFactoryUtils {
private static final Log logger = LogFactory.getLog(SessionFactoryUtils.class);
/**
* Get a TopLink Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using TopLinkTransactionManager. Will create a new Session
* otherwise, if "allowCreate" is true
.
*
This is the getSession
method used by typical data access code,
* in combination with releaseSession
called when done with
* the Session. Note that TopLinkTemplate allows to write data access code
* without caring about such resource handling.
* @param sessionFactory TopLink SessionFactory to create the session with
* @param allowCreate if a non-transactional Session should be created when no
* transactional Session can be found for the current thread
* @return the TopLink Session
* @throws DataAccessResourceFailureException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and
* "allowCreate" is false
* @see #releaseSession
* @see TopLinkTemplate
*/
public static Session getSession(SessionFactory sessionFactory, boolean allowCreate)
throws DataAccessResourceFailureException, IllegalStateException {
try {
return doGetSession(sessionFactory, allowCreate);
}
catch (TopLinkException ex) {
throw new DataAccessResourceFailureException("Could not open TopLink Session", ex);
}
}
/**
* Get a TopLink Session for the given SessionFactory. Is aware of and will
* return any existing corresponding Session bound to the current thread, for
* example when using TopLinkTransactionManager. Will create a new Session
* otherwise, if "allowCreate" is true
.
*
Same as getSession
, but throwing the original TopLinkException.
* @param sessionFactory TopLink SessionFactory to create the session with
* @param allowCreate if a non-transactional Session should be created when no
* transactional Session can be found for the current thread
* @return the TopLink Session
* @throws TopLinkException if the Session couldn't be created
* @throws IllegalStateException if no thread-bound Session found and
* "allowCreate" is false
* @see #releaseSession
* @see TopLinkTemplate
*/
public static Session doGetSession(SessionFactory sessionFactory, boolean allowCreate)
throws TopLinkException, IllegalStateException {
Assert.notNull(sessionFactory, "No SessionFactory specified");
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if (sessionHolder != null) {
return sessionHolder.getSession();
}
if (!allowCreate && !TransactionSynchronizationManager.isSynchronizationActive()) {
throw new IllegalStateException("No TopLink Session bound to thread, " +
"and configuration does not allow creation of non-transactional one here");
}
logger.debug("Creating TopLink Session");
Session session = sessionFactory.createSession();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
logger.debug("Registering new Spring transaction synchronization for new TopLink Session");
// Use same Session for further TopLink actions within the transaction.
// Thread object will get removed by synchronization at transaction completion.
sessionHolder = new SessionHolder(session);
sessionHolder.setSynchronizedWithTransaction(true);
TransactionSynchronizationManager.registerSynchronization(
new SessionSynchronization(sessionHolder, sessionFactory));
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}
return session;
}
/**
* Return whether the given TopLink Session is transactional, that is,
* bound to the current thread by Spring's transaction facilities.
* @param session the TopLink Session to check
* @param sessionFactory TopLink SessionFactory that the Session was created with
* (can be null
)
* @return whether the Session is transactional
*/
public static boolean isSessionTransactional(Session session, SessionFactory sessionFactory) {
if (sessionFactory == null) {
return false;
}
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
return (sessionHolder != null && session == sessionHolder.getSession());
}
/**
* Convert the given TopLinkException to an appropriate exception from the
* org.springframework.dao
hierarchy.
* @param ex TopLinkException that occured
* @return the corresponding DataAccessException instance
*/
public static DataAccessException convertTopLinkAccessException(TopLinkException ex) {
if (ex instanceof DatabaseException) {
// SQLException during TopLink access: only passed in here from custom code,
// as TopLinkTemplate will use SQLExceptionTranslator-based handling.
return new TopLinkJdbcException((DatabaseException) ex);
}
if (ex instanceof OptimisticLockException) {
return new TopLinkOptimisticLockingFailureException((OptimisticLockException) ex);
}
if (ex instanceof QueryException) {
return new TopLinkQueryException((QueryException) ex);
}
if (ex instanceof ConcurrencyException) {
return new ConcurrencyFailureException(ex.getMessage(), ex);
}
if (ex instanceof ConversionException) {
return new TypeMismatchDataAccessException(ex.getMessage(), ex);
}
// fallback
return new TopLinkSystemException(ex);
}
/**
* Close the given Session, created via the given factory,
* if it is not managed externally (i.e. not bound to the thread).
* @param session the TopLink Session to close
* @param sessionFactory TopLink SessionFactory that the Session was created with
* (can be null
)
*/
public static void releaseSession(Session session, SessionFactory sessionFactory) {
if (session == null) {
return;
}
// Only release non-transactional Sessions.
if (!isSessionTransactional(session, sessionFactory)) {
doRelease(session);
}
}
/**
* Perform the actual releasing of the TopLink Session.
* @param session the TopLink Session to release
*/
private static void doRelease(Session session) {
if (session != null) {
logger.debug("Closing TopLink Session");
try {
session.release();
}
catch (TopLinkException ex) {
logger.debug("Could not close TopLink Session", ex);
}
catch (Throwable ex) {
logger.debug("Unexpected exception on closing TopLink Session", ex);
}
}
}
/**
* Callback for resource cleanup at the end of a Spring-managed JTA transaction,
* i.e. when participating in a JtaTransactionManager transaction.
* @see org.springframework.transaction.jta.JtaTransactionManager
*/
private static class SessionSynchronization extends TransactionSynchronizationAdapter {
private final SessionHolder sessionHolder;
private final SessionFactory sessionFactory;
private boolean holderActive = true;
private SessionSynchronization(SessionHolder sessionHolder, SessionFactory sessionFactory) {
this.sessionHolder = sessionHolder;
this.sessionFactory = sessionFactory;
}
public void suspend() {
if (this.holderActive) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}
}
public void resume() {
if (this.holderActive) {
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
}
}
public void beforeCompletion() {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
this.holderActive = false;
}
public void afterCompletion(int status) {
releaseSession(this.sessionHolder.getSession(), this.sessionFactory);
}
}
}