FileDocCategorySizeDatePackage
JTATransaction.javaAPI DocHibernate 3.2.59549Sat Mar 11 11:17:44 GMT 2006org.hibernate.transaction

JTATransaction

public class JTATransaction extends Object implements org.hibernate.Transaction
Implements a basic transaction strategy for JTA transactions. Instances check to see if there is an existing JTA transaction. If none exists, a new transaction is started. If one exists, all work is done in the existing context. The following properties are used to locate the underlying UserTransaction:

hibernate.jndi.urlJNDI initial context URL
hibernate.jndi.classJNDI provider class
jta.UserTransactionJNDI name
author
Gavin King

Fields Summary
private static final Log
log
private final org.hibernate.jdbc.JDBCContext
jdbcContext
private final TransactionFactory.Context
transactionContext
private UserTransaction
ut
private boolean
newTransaction
private boolean
begun
private boolean
commitFailed
private boolean
commitSucceeded
private boolean
callback
private static final int
NULL
Constructors Summary
public JTATransaction(InitialContext context, String utName, org.hibernate.jdbc.JDBCContext jdbcContext, TransactionFactory.Context transactionContext)

	
	 
			  
			  
			  
			 
	 
		this.jdbcContext = jdbcContext;
		this.transactionContext = transactionContext;

		log.debug("Looking for UserTransaction under: " + utName);
		
		try {
			ut = (UserTransaction) context.lookup(utName);
		}
		catch (NamingException ne) {
			log.error("Could not find UserTransaction in JNDI", ne);
			throw new TransactionException("Could not find UserTransaction in JNDI: ", ne);
		}
		if (ut==null) {
			throw new AssertionFailure("A naming service lookup returned null");
		}

		log.debug("Obtained UserTransaction");
	
Methods Summary
private voidafterCommitRollback()


	     
		
		begun = false;

		if (callback) { // this method is a noop if there is a Synchronization!

			if (!newTransaction) {
				log.warn("You should set hibernate.transaction.manager_lookup_class if cache is enabled");
			}
			int status=NULL;
			try {
				status = ut.getStatus();
			}
			catch (Exception e) {
				log.error("Could not determine transaction status after commit", e);
				throw new TransactionException("Could not determine transaction status after commit", e);
			}
			finally {
				/*if (status!=Status.STATUS_COMMITTED && status!=Status.STATUS_ROLLEDBACK) {
					log.warn("Transaction not complete - you should set hibernate.transaction.manager_lookup_class if cache is enabled");
					//throw exception??
				}*/
				jdbcContext.afterTransactionCompletion(status==Status.STATUS_COMMITTED, this);
			}

		}
	
public voidbegin()

		if (begun) {
			return;
		}
		if (commitFailed) {
			throw new TransactionException("cannot re-start transaction after failed commit");
		}
		
		log.debug("begin");

		try {
			newTransaction = ut.getStatus() == Status.STATUS_NO_TRANSACTION;
			if (newTransaction) {
				ut.begin();
				log.debug("Began a new JTA transaction");
			}
		}
		catch (Exception e) {
			log.error("JTA transaction begin failed", e);
			throw new TransactionException("JTA transaction begin failed", e);
		}

		/*if (newTransaction) {
			// don't need a synchronization since we are committing
			// or rolling back the transaction ourselves - assuming
			// that we do no work in beforeTransactionCompletion()
			synchronization = false;
		}*/

		boolean synchronization = jdbcContext.registerSynchronizationIfPossible();

		if ( !newTransaction && !synchronization ) {
			log.warn("You should set hibernate.transaction.manager_lookup_class if cache is enabled");
		}

		if (!synchronization) {
			//if we could not register a synchronization,
			//do the before/after completion callbacks
			//ourself (but we need to let jdbcContext
			//know that this is what we are going to
			//do, so it doesn't keep trying to register
			//synchronizations)
			callback = jdbcContext.registerCallbackIfNecessary();
		}

		begun = true;
		commitSucceeded = false;
		
		jdbcContext.afterTransactionBegin(this);
	
private voidcloseIfRequired()

		boolean close = callback && 
				transactionContext.shouldAutoClose() && 
				!transactionContext.isClosed();
		if ( close ) {
			transactionContext.managedClose();
		}
	
public voidcommit()

		if (!begun) {
			throw new TransactionException("Transaction not successfully started");
		}

		log.debug("commit");

		boolean flush = !transactionContext.isFlushModeNever()
		        && ( callback || !transactionContext.isFlushBeforeCompletionEnabled() );

		if (flush) {
			transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
		}

		if (callback && newTransaction) {
			jdbcContext.beforeTransactionCompletion(this);
		}

		closeIfRequired();

		if (newTransaction) {
			try {
				ut.commit();
				commitSucceeded = true;
				log.debug("Committed JTA UserTransaction");
			}
			catch (Exception e) {
				commitFailed = true; // so the transaction is already rolled back, by JTA spec
				log.error("JTA commit failed", e);
				throw new TransactionException("JTA commit failed: ", e);
			}
			finally {
				afterCommitRollback();
			}
		}
		else {
			// this one only really needed for badly-behaved applications!
			// (if the TransactionManager has a Sychronization registered,
			// its a noop)
			// (actually we do need it for downgrading locks)
			afterCommitRollback();
		}

	
private javax.transaction.TransactionManagergetTransactionManager()

		return transactionContext.getFactory().getTransactionManager();
	
protected javax.transaction.UserTransactiongetUserTransaction()

		return ut;
	
public booleanisActive()


		if (!begun || commitFailed || commitSucceeded) return false;

		final int status;
		try {
			status = ut.getStatus();
		}
		catch (SystemException se) {
			log.error("Could not determine transaction status", se);
			throw new TransactionException("Could not determine transaction status: ", se);
		}
		if (status==Status.STATUS_UNKNOWN) {
			throw new TransactionException("Could not determine transaction status");
		}
		else {
			return status==Status.STATUS_ACTIVE;
		}
	
public voidregisterSynchronization(javax.transaction.Synchronization sync)

		if (getTransactionManager()==null) {
			throw new IllegalStateException("JTA TransactionManager not available");
		}
		else {
			try {
				getTransactionManager().getTransaction().registerSynchronization(sync);
			}
			catch (Exception e) {
				throw new TransactionException("could not register synchronization", e);
			}
		}
	
public voidrollback()

		if (!begun && !commitFailed) {
			throw new TransactionException("Transaction not successfully started");
		}

		log.debug("rollback");

		/*if (!synchronization && newTransaction && !commitFailed) {
			jdbcContext.beforeTransactionCompletion(this);
		}*/

		try {
			closeIfRequired();
		}
		catch (Exception e) {
			log.error("could not close session during rollback", e);
			//swallow it, and continue to roll back JTA transaction
		}

		try {
			if (newTransaction) {
				if (!commitFailed) {
					ut.rollback();
					log.debug("Rolled back JTA UserTransaction");
				}
			}
			else {
				ut.setRollbackOnly();
				log.debug("set JTA UserTransaction to rollback only");
			}
		}
		catch (Exception e) {
			log.error("JTA rollback failed", e);
			throw new TransactionException("JTA rollback failed", e);
		}
		finally {
			afterCommitRollback();
		}
	
public voidsetTimeout(int seconds)

		try {
			ut.setTransactionTimeout(seconds);
		}
		catch (SystemException se) {
			throw new TransactionException("could not set transaction timeout", se);
		}
	
public booleanwasCommitted()


		//if (!begun || commitFailed) return false;

		final int status;
		try {
			status = ut.getStatus();
		}
		catch (SystemException se) {
			log.error("Could not determine transaction status", se);
			throw new TransactionException("Could not determine transaction status: ", se);
		}
		if (status==Status.STATUS_UNKNOWN) {
			throw new TransactionException("Could not determine transaction status");
		}
		else {
			return status==Status.STATUS_COMMITTED;
		}
	
public booleanwasRolledBack()


		//if (!begun) return false;
		//if (commitFailed) return true;

		final int status;
		try {
			status = ut.getStatus();
		}
		catch (SystemException se) {
			log.error("Could not determine transaction status", se);
			throw new TransactionException("Could not determine transaction status", se);
		}
		if (status==Status.STATUS_UNKNOWN) {
			throw new TransactionException("Could not determine transaction status");
		}
		else {
			return JTAHelper.isRollback(status);
		}