[hibernate-commits] Hibernate SVN: r14893 - core/branches/Branch_3_2/src/org/hibernate/transaction.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Jul 8 11:36:59 EDT 2008


Author: steve.ebersole at jboss.com
Date: 2008-07-08 11:36:59 -0400 (Tue, 08 Jul 2008)
New Revision: 14893

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

Modified: core/branches/Branch_3_2/src/org/hibernate/transaction/JTATransaction.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/transaction/JTATransaction.java	2008-07-08 13:08:34 UTC (rev 14892)
+++ core/branches/Branch_3_2/src/org/hibernate/transaction/JTATransaction.java	2008-07-08 15:36:59 UTC (rev 14893)
@@ -1,8 +1,29 @@
-//$Id$
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
 package org.hibernate.transaction;
 
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
 import javax.transaction.Status;
 import javax.transaction.Synchronization;
 import javax.transaction.SystemException;
@@ -11,7 +32,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.hibernate.AssertionFailure;
+
 import org.hibernate.HibernateException;
 import org.hibernate.Transaction;
 import org.hibernate.TransactionException;
@@ -19,17 +40,14 @@
 import org.hibernate.util.JTAHelper;
 
 /**
- * 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 <tt>UserTransaction</tt>:
- * <br><br>
- * <table>
- * <tr><td><tt>hibernate.jndi.url</tt></td><td>JNDI initial context URL</td></tr>
- * <tr><td><tt>hibernate.jndi.class</tt></td><td>JNDI provider class</td></tr>
- * <tr><td><tt>jta.UserTransaction</tt></td><td>JNDI name</td></tr>
- * </table>
+ * {@link Transaction} implementation based on transaction management through
+ * a JTA {@link UserTransaction}.  Similar to {@link CMTTransaction}, except
+ * here we are actually managing the transactions through the Hibernate
+ * transaction mechanism.
+ *
  * @author Gavin King
+ * @author Steve Ebersole
+ * @author Les Hazlewood
  */
 public class JTATransaction implements Transaction {
 
@@ -38,36 +56,20 @@
 	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;
 	}
 
 	public void begin() throws HibernateException {
@@ -81,9 +83,9 @@
 		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");
 			}
 		}
@@ -143,7 +145,7 @@
 
 		if (newTransaction) {
 			try {
-				ut.commit();
+				userTransaction.commit();
 				commitSucceeded = true;
 				log.debug("Committed JTA UserTransaction");
 			}
@@ -188,12 +190,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");
 			}
 		}
@@ -219,7 +221,7 @@
 			}
 			int status=NULL;
 			try {
-				status = ut.getStatus();
+				status = userTransaction.getStatus();
 			}
 			catch (Exception e) {
 				log.error("Could not determine transaction status after commit", e);
@@ -243,7 +245,7 @@
 
 		final int status;
 		try {
-			status = ut.getStatus();
+			status = userTransaction.getStatus();
 		}
 		catch (SystemException se) {
 			log.error("Could not determine transaction status", se);
@@ -263,7 +265,7 @@
 
 		final int status;
 		try {
-			status = ut.getStatus();
+			status = userTransaction.getStatus();
 		}
 		catch (SystemException se) {
 			log.error("Could not determine transaction status", se);
@@ -283,7 +285,7 @@
 
 		final int status;
 		try {
-			status = ut.getStatus();
+			status = userTransaction.getStatus();
 		}
 		catch (SystemException se) {
 			log.error("Could not determine transaction status", se);
@@ -326,7 +328,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);
@@ -334,6 +336,6 @@
 	}
 
 	protected UserTransaction getUserTransaction() {
-		return ut;
+		return userTransaction;
 	}
 }

Modified: core/branches/Branch_3_2/src/org/hibernate/transaction/JTATransactionFactory.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/transaction/JTATransactionFactory.java	2008-07-08 13:08:34 UTC (rev 14892)
+++ core/branches/Branch_3_2/src/org/hibernate/transaction/JTATransactionFactory.java	2008-07-08 15:36:59 UTC (rev 14893)
@@ -1,4 +1,27 @@
-//$Id$
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ *
+ */
 package org.hibernate.transaction;
 
 import java.util.Properties;
@@ -20,61 +43,184 @@
 import org.hibernate.util.JTAHelper;
 
 /**
- * Factory for <tt>JTATransaction</tt>.
+ * 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.
  *
- * @see JTATransaction
  * @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 Log log = LogFactory.getLog(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 [" + userTransactionName + "] for UserTransaction JDNI namespace" );
+	}
+
+	/**
+	 * 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);
+		catch ( NamingException 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( properties );
+			if ( lookup != null ) {
+				utName = lookup.getUserTransactionName();
+			}
+		}
+		return utName == null ? DEFAULT_USER_TRANSACTION_NAME : utName;
+	}
 
-		if (utName==null) {
-			TransactionManagerLookup lookup = TransactionManagerLookupFactory.getTransactionManagerLookup(props);
-			if (lookup!=null) utName = lookup.getUserTransactionName();
+	/**
+	 * {@inheritDoc}
+	 */
+	public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
+			throws HibernateException {
+		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 );
+		}
+	}
 
-		if (utName==null) utName = DEFAULT_USER_TRANSACTION_NAME;
+	/**
+	 * Getter for property 'initialContext'.
+	 *
+	 * @return Value for property 'initialContext'.
+	 */
+	protected InitialContext getInitialContext() {
+		return initialContext;
 	}
 
-	public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
-	throws HibernateException {
-		return new JTATransaction(context, utName, jdbcContext, transactionContext);
+	/**
+	 * 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,
-	        Transaction transaction) {
+			Context transactionContext,
+			Transaction transaction) {
 		try {
-            // Essentially:
+			// Essentially:
 			// 1) If we have a local (Hibernate) transaction in progress
 			//      and it already has the UserTransaction cached, use that
 			//      UserTransaction to determine the status.
@@ -83,27 +229,22 @@
 			// 3) Finally, as the last resort, try to lookup the
 			//      UserTransaction via JNDI and use that to determine the
 			//      status.
-            if ( transaction != null ) {
+			if ( transaction != null ) {
 				UserTransaction ut = ( ( JTATransaction ) transaction ).getUserTransaction();
-                if ( ut != null ) {
-                    return JTAHelper.isInProgress( ut.getStatus() );
-                }
-            }
+				if ( ut != null ) {
+					return JTAHelper.isInProgress( ut.getStatus() );
+				}
+			}
 
-            if ( jdbcContext.getFactory().getTransactionManager() != null ) {
-                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 );
-				}
-            }
+			if ( jdbcContext.getFactory().getTransactionManager() != null ) {
+				return JTAHelper.isInProgress( jdbcContext.getFactory().getTransactionManager().getStatus() );
+			}
+			else {
+				UserTransaction ut = getUserTransaction();
+				return ut != null && JTAHelper.isInProgress( ut.getStatus() );
+			}
 		}
-		catch( SystemException se ) {
+		catch ( SystemException se ) {
 			throw new TransactionException( "Unable to check transaction status", se );
 		}
 	}




More information about the hibernate-commits mailing list