[hibernate-commits] Hibernate SVN: r14895 - core/trunk/core/src/main/java/org/hibernate/transaction.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Jul 8 11:38:44 EDT 2008


Author: steve.ebersole at jboss.com
Date: 2008-07-08 11:38:44 -0400 (Tue, 08 Jul 2008)
New Revision: 14895

Modified:
   core/trunk/core/src/main/java/org/hibernate/transaction/JTATransaction.java
   core/trunk/core/src/main/java/org/hibernate/transaction/JTATransactionFactory.java
Log:
HHH-3358 : non-JNDI distributed transaction support

Modified: core/trunk/core/src/main/java/org/hibernate/transaction/JTATransaction.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/transaction/JTATransaction.java	2008-07-08 15:37:42 UTC (rev 14894)
+++ core/trunk/core/src/main/java/org/hibernate/transaction/JTATransaction.java	2008-07-08 15:38:44 UTC (rev 14895)
@@ -23,8 +23,6 @@
  */
 package org.hibernate.transaction;
 
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
 import javax.transaction.Status;
 import javax.transaction.Synchronization;
 import javax.transaction.SystemException;
@@ -33,7 +31,6 @@
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.hibernate.AssertionFailure;
 import org.hibernate.HibernateException;
 import org.hibernate.Transaction;
 import org.hibernate.TransactionException;
@@ -45,17 +42,10 @@
  * a JTA {@link UserTransaction}.  Similar to {@link CMTTransaction}, except
  * here we are actually managing the transactions through the Hibernate
  * transaction mechanism.
- * <p/>
- * 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
- * {@link UserTransaction}:<ul>
- * <li><tt>hibernate.jndi.url</tt> : JNDI initial context URL</li>
- * <li><tt>hibernate.jndi.class</tt> : JNDI provider class</li>
- * <li><tt>jta.UserTransaction</tt> : JNDI namespace</li>
- * </ul>
  *
  * @author Gavin King
+ * @author Steve Ebersole
+ * @author Les Hazlewood
  */
 public class JTATransaction implements Transaction {
 
@@ -64,39 +54,23 @@
 	private final JDBCContext jdbcContext;
 	private final TransactionFactory.Context transactionContext;
 
-	private UserTransaction ut;
+	private UserTransaction userTransaction;
 	private boolean newTransaction;
 	private boolean begun;
 	private boolean commitFailed;
 	private boolean commitSucceeded;
 	private boolean callback;
-	
-	public JTATransaction(
-			InitialContext context, 
-			String utName, 
-			JDBCContext jdbcContext, 
-			TransactionFactory.Context transactionContext
-	) {
+
+    public JTATransaction(
+			UserTransaction userTransaction,
+			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");
+        this.userTransaction = userTransaction;
 	}
 
-	/**
+    /**
 	 * {@inheritDoc}
 	 */
 	public void begin() throws HibernateException {
@@ -106,13 +80,13 @@
 		if (commitFailed) {
 			throw new TransactionException("cannot re-start transaction after failed commit");
 		}
-		
+
 		log.debug("begin");
 
 		try {
-			newTransaction = ut.getStatus() == Status.STATUS_NO_TRANSACTION;
+			newTransaction = userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION;
 			if (newTransaction) {
-				ut.begin();
+				userTransaction.begin();
 				log.debug("Began a new JTA transaction");
 			}
 		}
@@ -146,7 +120,7 @@
 
 		begun = true;
 		commitSucceeded = false;
-		
+
 		jdbcContext.afterTransactionBegin(this);
 	}
 
@@ -175,7 +149,7 @@
 
 		if (newTransaction) {
 			try {
-				ut.commit();
+				userTransaction.commit();
 				commitSucceeded = true;
 				log.debug("Committed JTA UserTransaction");
 			}
@@ -223,12 +197,12 @@
 		try {
 			if (newTransaction) {
 				if (!commitFailed) {
-					ut.rollback();
+					userTransaction.rollback();
 					log.debug("Rolled back JTA UserTransaction");
 				}
 			}
 			else {
-				ut.setRollbackOnly();
+				userTransaction.setRollbackOnly();
 				log.debug("set JTA UserTransaction to rollback only");
 			}
 		}
@@ -244,7 +218,7 @@
 	private static final int NULL = Integer.MIN_VALUE;
 
 	private void afterCommitRollback() throws TransactionException {
-		
+
 		begun = false;
 
 		if (callback) { // this method is a noop if there is a Synchronization!
@@ -254,7 +228,7 @@
 			}
 			int status=NULL;
 			try {
-				status = ut.getStatus();
+				status = userTransaction.getStatus();
 			}
 			catch (Exception e) {
 				log.error("Could not determine transaction status after commit", e);
@@ -275,13 +249,9 @@
 	 * {@inheritDoc}
 	 */
 	public boolean wasRolledBack() throws TransactionException {
-
-		//if (!begun) return false;
-		//if (commitFailed) return true;
-
 		final int status;
 		try {
-			status = ut.getStatus();
+			status = userTransaction.getStatus();
 		}
 		catch (SystemException se) {
 			log.error("Could not determine transaction status", se);
@@ -299,12 +269,9 @@
 	 * {@inheritDoc}
 	 */
 	public boolean wasCommitted() throws TransactionException {
-
-		//if (!begun || commitFailed) return false;
-
 		final int status;
 		try {
-			status = ut.getStatus();
+			status = userTransaction.getStatus();
 		}
 		catch (SystemException se) {
 			log.error("Could not determine transaction status", se);
@@ -317,7 +284,7 @@
 			return status==Status.STATUS_COMMITTED;
 		}
 	}
-	
+
 	/**
 	 * {@inheritDoc}
 	 */
@@ -327,7 +294,7 @@
 
 		final int status;
 		try {
-			status = ut.getStatus();
+			status = userTransaction.getStatus();
 		}
 		catch (SystemException se) {
 			log.error("Could not determine transaction status", se);
@@ -368,8 +335,8 @@
 	}
 
 	private void closeIfRequired() throws HibernateException {
-		boolean close = callback && 
-				transactionContext.shouldAutoClose() && 
+		boolean close = callback &&
+				transactionContext.shouldAutoClose() &&
 				!transactionContext.isClosed();
 		if ( close ) {
 			transactionContext.managedClose();
@@ -381,7 +348,7 @@
 	 */
 	public void setTimeout(int seconds) {
 		try {
-			ut.setTransactionTimeout(seconds);
+			userTransaction.setTransactionTimeout(seconds);
 		}
 		catch (SystemException se) {
 			throw new TransactionException("could not set transaction timeout", se);
@@ -394,6 +361,6 @@
 	 * @return Value for property 'userTransaction'.
 	 */
 	protected UserTransaction getUserTransaction() {
-		return ut;
+		return userTransaction;
 	}
 }

Modified: core/trunk/core/src/main/java/org/hibernate/transaction/JTATransactionFactory.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/transaction/JTATransactionFactory.java	2008-07-08 15:37:42 UTC (rev 14894)
+++ core/trunk/core/src/main/java/org/hibernate/transaction/JTATransactionFactory.java	2008-07-08 15:38:44 UTC (rev 14895)
@@ -44,57 +44,177 @@
 
 /**
  * Factory for {@link JTATransaction} instances.
+ * <p/>
+ * To be completely accurate to the JTA spec, JTA implementations should
+ * publish their contextual {@link UserTransaction} reference into JNDI.
+ * However, in practice there are quite a few <tt>stand-alone</tt>
+ * implementations intended for use outside of J2EE/JEE containers and
+ * which therefore do not publish their {@link UserTransaction} references
+ * into JNDI but which otherwise follow the aspects of the JTA specification.
+ * This {@link TransactionFactory} implementation can support both models.
+ * <p/>
+ * For complete JTA implementations (including dependence on JNDI), the
+ * {@link UserTransaction} reference is obtained by a call to
+ * {@link #resolveInitialContext}.  Hibernate will then attempt to locate the
+ * {@link UserTransaction} within this resolved
+ * {@link InitialContext} based on the namespace returned by
+ * {@link #resolveUserTransactionName}.
+ * <p/>
+ * For the so-called <tt>stand-alone</tt> implementations, we do not care at
+ * all about the JNDI aspects just described.  Here, the implementation would
+ * have a specific manner to obtain a reference to its contextual
+ * {@link UserTransaction}; usually this would be a static code reference, but
+ * again it varies.  Anyway, for each implementation the integration would need
+ * to override the {@link #getUserTransaction} method and return the appropriate
+ * thing.
  *
  * @author Gavin King
+ * @author Steve Ebersole
+ * @author Les Hazlewood
  */
 public class JTATransactionFactory implements TransactionFactory {
-
+	public static final String DEFAULT_USER_TRANSACTION_NAME = "java:comp/UserTransaction";
 	private static final Logger log = LoggerFactory.getLogger( JTATransactionFactory.class );
-	private static final String DEFAULT_USER_TRANSACTION_NAME = "java:comp/UserTransaction";
 
-	protected InitialContext context;
-	protected String utName;
+	protected InitialContext initialContext;
+	protected String userTransactionName;
 
+	/**
+	 * Configure this transaction factory.  Specifically here we are attempting to
+	 * resolve both an {@link #getInitialContext InitialContext} as well as the
+	 * {@link #getUserTransactionName() JNDI namespace} for the {@link UserTransaction}.
+	 *
+	 * @param props The configuration properties
+	 *
+	 * @exception HibernateException
+	 */
 	public void configure(Properties props) throws HibernateException {
+		this.initialContext = resolveInitialContext( props );
+		this.userTransactionName = resolveUserTransactionName( props );
+		log.trace( "Configured JTATransactionFactory to use [{}] for UserTransaction JDNI namespace", userTransactionName );
+	}
+
+	/**
+	 * Given the lot of Hibernate configuration properties, resolve appropriate
+	 * reference to JNDI {@link InitialContext}.
+	 * <p/>
+	 * In general, the properties in which we are interested here all begin with
+	 * <tt>hibernate.jndi</tt>.  Especially important depending on your
+	 * environment are {@link Environment#JNDI_URL hibernate.jndi.url} and
+	 *  {@link Environment#JNDI_CLASS hibernate.jndi.class}
+	 *
+	 * @param properties The Hibernate config properties.
+	 * @return The resolved InitialContext.
+	 */
+	protected final InitialContext resolveInitialContext(Properties properties) {
 		try {
-			context = NamingHelper.getInitialContext( props );
+			return NamingHelper.getInitialContext( properties );
 		}
 		catch ( NamingException ne ) {
-			log.error( "Could not obtain initial context", ne );
 			throw new HibernateException( "Could not obtain initial context", ne );
 		}
+	}
 
-		utName = props.getProperty( Environment.USER_TRANSACTION );
-
+	/**
+	 * Given the lot of Hibernate configuration properties, resolve appropriate
+	 * JNDI namespace to use for {@link UserTransaction} resolution.
+	 * <p/>
+	 * We determine the namespace to use by<ol>
+	 * <li>Any specified {@link Environment#USER_TRANSACTION jta.UserTransaction} config property</li>
+	 * <li>If a {@link TransactionManagerLookup} was indicated, use its
+	 * {@link TransactionManagerLookup#getUserTransactionName}</li>
+	 * <li>finally, as a last resort, we use {@link #DEFAULT_USER_TRANSACTION_NAME}</li>
+	 * </ol>
+	 *
+	 * @param properties The Hibernate config properties.
+	 * @return The resolved {@link UserTransaction} namespace
+	 */
+	protected final String resolveUserTransactionName(Properties properties) {
+		String utName = properties.getProperty( Environment.USER_TRANSACTION );
 		if ( utName == null ) {
-			TransactionManagerLookup lookup = TransactionManagerLookupFactory.getTransactionManagerLookup( props );
+			TransactionManagerLookup lookup = TransactionManagerLookupFactory.getTransactionManagerLookup( properties );
 			if ( lookup != null ) {
 				utName = lookup.getUserTransactionName();
 			}
 		}
-
-		if ( utName == null ) {
-			utName = DEFAULT_USER_TRANSACTION_NAME;
-		}
+		return utName == null ? DEFAULT_USER_TRANSACTION_NAME : utName;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
 			throws HibernateException {
-		return new JTATransaction( context, utName, jdbcContext, transactionContext );
+		UserTransaction ut = getUserTransaction();
+		return new JTATransaction( ut, jdbcContext, transactionContext );
 	}
 
+	/**
+	 * Get the {@link UserTransaction} reference.
+	 *
+	 * @return The appropriate {@link UserTransaction} reference.
+	 */
+	protected UserTransaction getUserTransaction() {
+		log.trace( "Attempting to locate UserTransaction via JNDI [{}]", getUserTransactionName() );
+
+		try {
+			UserTransaction ut = ( UserTransaction ) getInitialContext().lookup( getUserTransactionName() );
+			if ( ut == null ) {
+				throw new TransactionException( "Naming service lookup for UserTransaction returned null [" + getUserTransactionName() +"]" );
+			}
+
+			log.trace( "Obtained UserTransaction" );
+
+			return ut;
+		}
+		catch ( NamingException ne ) {
+			throw new TransactionException( "Could not find UserTransaction in JNDI [" + getUserTransaction() + "]", ne );
+		}
+	}
+
+	/**
+	 * Getter for property 'initialContext'.
+	 *
+	 * @return Value for property 'initialContext'.
+	 */
+	protected InitialContext getInitialContext() {
+		return initialContext;
+	}
+
+	/**
+	 * Getter for property 'userTransactionName'.
+	 * The algorithm here is
+	 *
+	 * @return Value for property 'userTransactionName'.
+	 */
+	protected String getUserTransactionName() {
+		return userTransactionName;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
 	public ConnectionReleaseMode getDefaultReleaseMode() {
 		return ConnectionReleaseMode.AFTER_STATEMENT;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public boolean isTransactionManagerRequired() {
 		return false;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public boolean areCallbacksLocalToHibernateTransactions() {
 		return false;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	public boolean isTransactionInProgress(
 			JDBCContext jdbcContext,
 			Context transactionContext,
@@ -120,13 +240,8 @@
 				return JTAHelper.isInProgress( jdbcContext.getFactory().getTransactionManager().getStatus() );
 			}
 			else {
-				try {
-					UserTransaction ut = ( UserTransaction ) context.lookup( utName );
-					return ut != null && JTAHelper.isInProgress( ut.getStatus() );
-				}
-				catch ( NamingException ne ) {
-					throw new TransactionException( "Unable to locate UserTransaction to check status", ne );
-				}
+				UserTransaction ut = getUserTransaction();
+				return ut != null && JTAHelper.isInProgress( ut.getStatus() );
 			}
 		}
 		catch ( SystemException se ) {




More information about the hibernate-commits mailing list