package org.hibernate.engine.transaction.internal.jta;
import java.sql.Connection;
import java.sql.SQLException;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.transaction.spi.IsolationDelegate;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.jdbc.WorkExecutorVisitable;
public class JtaIsolationDelegate implements IsolationDelegate {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JtaIsolationDelegate.class );
private final TransactionCoordinator transactionCoordinator;
public JtaIsolationDelegate(TransactionCoordinator transactionCoordinator) {
this.transactionCoordinator = transactionCoordinator;
}
protected TransactionManager transactionManager() {
return transactionCoordinator.getTransactionContext()
.getTransactionEnvironment()
.getJtaPlatform()
.retrieveTransactionManager();
}
protected JdbcConnectionAccess jdbcConnectionAccess() {
return transactionCoordinator.getTransactionContext().getJdbcConnectionAccess();
}
protected SqlExceptionHelper sqlExceptionHelper() {
return transactionCoordinator.getTransactionContext()
.getTransactionEnvironment()
.getJdbcServices()
.getSqlExceptionHelper();
}
@Override
public <T> T delegateWork(WorkExecutorVisitable<T> work, boolean transacted) throws HibernateException {
TransactionManager transactionManager = transactionManager();
try {
Transaction surroundingTransaction = transactionManager.suspend();
LOG.debugf( "Surrounding JTA transaction suspended [%s]", surroundingTransaction );
boolean hadProblems = false;
try {
if ( transacted ) {
return doTheWorkInNewTransaction( work, transactionManager );
}
else {
return doTheWorkInNoTransaction( work );
}
}
catch ( HibernateException e ) {
hadProblems = true;
throw e;
}
finally {
try {
transactionManager.resume( surroundingTransaction );
LOG.debugf( "Surrounding JTA transaction resumed [%s]", surroundingTransaction );
}
catch( Throwable t ) {
if ( !hadProblems ) {
throw new HibernateException( "Unable to resume previously suspended transaction", t );
}
}
}
}
catch ( SystemException e ) {
throw new HibernateException( "Unable to suspend current JTA transaction", e );
}
}
private <T> T doTheWorkInNewTransaction(WorkExecutorVisitable<T> work, TransactionManager transactionManager) {
try {
transactionManager.begin();
try {
T result = doTheWork( work );
transactionManager.commit();
return result;
}
catch ( Exception e ) {
try {
transactionManager.rollback();
}
catch ( Exception ignore ) {
LOG.unableToRollbackIsolatedTransaction( e, ignore );
}
throw new HibernateException( "Could not apply work", e );
}
}
catch ( SystemException e ) {
throw new HibernateException( "Unable to start isolated transaction", e );
}
catch ( NotSupportedException e ) {
throw new HibernateException( "Unable to start isolated transaction", e );
}
}
private <T> T doTheWorkInNoTransaction(WorkExecutorVisitable<T> work) {
return doTheWork( work );
}
private <T> T doTheWork(WorkExecutorVisitable<T> work) {
try {
Connection connection = jdbcConnectionAccess().obtainConnection();
try {
return work.accept( new WorkExecutor<T>(), connection );
}
catch ( HibernateException e ) {
throw e;
}
catch ( Exception e ) {
throw new HibernateException( "Unable to perform isolated work", e );
}
finally {
try {
jdbcConnectionAccess().releaseConnection( connection );
}
catch ( Throwable ignore ) {
LOG.unableToReleaseIsolatedConnection( ignore );
}
}
}
catch ( SQLException e ) {
throw sqlExceptionHelper().convert( e, "unable to obtain isolated JDBC connection" );
}
}
}