Author: steve.ebersole@(protected)
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)
@@(protected) @@
-//$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;
@@(protected) @@
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;
@@(protected) @@
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>
+ * {@(protected)
+ * a JTA {@(protected)
+ * 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 {
@@(protected) @@
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 {
@@(protected) @@
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");
}
}
@@(protected) @@
if (newTransaction) {
try {
- ut.commit();
+ userTransaction.commit();
commitSucceeded = true;
log.debug("Committed JTA UserTransaction");
}
@@(protected) @@
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");
}
}
@@(protected) @@
}
int status=NULL;
try {
- status = ut.getStatus();
+ status = userTransaction.getStatus();
}
catch (Exception e) {
log.error("Could not determine transaction status after commit", e);
@@(protected) @@
final int status;
try {
- status = ut.getStatus();
+ status = userTransaction.getStatus();
}
catch (SystemException se) {
log.error("Could not determine transaction status", se);
@@(protected) @@
final int status;
try {
- status = ut.getStatus();
+ status = userTransaction.getStatus();
}
catch (SystemException se) {
log.error("Could not determine transaction status", se);
@@(protected) @@
final int status;
try {
- status = ut.getStatus();
+ status = userTransaction.getStatus();
}
catch (SystemException se) {
log.error("Could not determine transaction status", se);
@@(protected) @@
public void setTimeout(int seconds) {
try {
- ut.setTransactionTimeout(seconds);
+ userTransaction.setTransactionTimeout(seconds);
}
catch (SystemException se) {
throw new TransactionException("could not set transaction timeout", se);
@@(protected) @@
}
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)
@@(protected) @@
-//$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;
@@(protected) @@
import
org.hibernate.util.JTAHelper;
/**
- * Factory for <tt>JTATransaction</tt>.
+ * Factory for {@(protected).
+ * <p/>
+ * To be completely accurate to the JTA spec, JTA implementations should
+ * publish their contextual {@(protected).
+ * 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 {@(protected)
+ * into JNDI but which otherwise follow the aspects of the JTA specification.
+ * This {@(protected).
+ * <p/>
+ * For complete JTA implementations (including dependence on JNDI), the
+ * {@(protected)
+ * {@(protected)
+ * {@(protected)
+ * {@(protected)
+ * {@(protected)}.
+ * <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
+ * {@(protected)
+ * again it varies. Anyway, for each implementation the integration would need
+ * to override the {@(protected)
+ * 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 {@(protected)
+ * {@(protected)}.
+ *
+ * @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 {@(protected)}.
+ * <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 {@(protected)
+ * {@(protected)}
+ *
+ * @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 {@(protected).
+ * <p/>
+ * We determine the namespace to use by<ol>
+ * <li>Any specified {@(protected)>
+ * <li>If a {@(protected)
+ * {@(protected)>
+ * <li>finally, as a last resort, we use {@(protected)>
+ * </ol>
+ *
+ * @param properties The Hibernate config properties.
+ * @return The resolved {@(protected)
+ */
+ 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();
+ /**
+ * {@(protected)}
+ */
+ public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
+ throws HibernateException {
+ UserTransaction ut = getUserTransaction();
+ return new JTATransaction( ut, jdbcContext, transactionContext );
+ }
+
+ /**
+ * Get the {@(protected).
+ *
+ * @return The appropriate {@(protected).
+ */
+ 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;
}
+ /**
+ * {@(protected)}
+ */
public ConnectionReleaseMode getDefaultReleaseMode() {
return ConnectionReleaseMode.AFTER_STATEMENT;
}
+ /**
+ * {@(protected)}
+ */
public boolean isTransactionManagerRequired() {
return false;
}
+ /**
+ * {@(protected)}
+ */
public boolean areCallbacksLocalToHibernateTransactions() {
return false;
}
+ /**
+ * {@(protected)}
+ */
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.
@@(protected) @@
// 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 );
}
}
_______________________________________________
hibernate-commits mailing list
hibernate-commits@(protected)
https://lists.jboss.org/mailman/listinfo/hibernate-commits