Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » transaction » [javadoc | source]
    1   /*
    2    * Hibernate, Relational Persistence for Idiomatic Java
    3    *
    4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
    5    * indicated by the @author tags or express copyright attribution
    6    * statements applied by the authors.  All third-party contributions are
    7    * distributed under license by Red Hat Middleware LLC.
    8    *
    9    * This copyrighted material is made available to anyone wishing to use, modify,
   10    * copy, or redistribute it subject to the terms and conditions of the GNU
   11    * Lesser General Public License, as published by the Free Software Foundation.
   12    *
   13    * This program is distributed in the hope that it will be useful,
   14    * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15    * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   16    * for more details.
   17    *
   18    * You should have received a copy of the GNU Lesser General Public License
   19    * along with this distribution; if not, write to:
   20    * Free Software Foundation, Inc.
   21    * 51 Franklin Street, Fifth Floor
   22    * Boston, MA  02110-1301  USA
   23    *
   24    */
   25   package org.hibernate.transaction;
   26   
   27   import java.util.Properties;
   28   
   29   import javax.naming.InitialContext;
   30   import javax.naming.NamingException;
   31   import javax.transaction.SystemException;
   32   import javax.transaction.UserTransaction;
   33   
   34   import org.slf4j.Logger;
   35   import org.slf4j.LoggerFactory;
   36   
   37   import org.hibernate.ConnectionReleaseMode;
   38   import org.hibernate.HibernateException;
   39   import org.hibernate.Transaction;
   40   import org.hibernate.TransactionException;
   41   import org.hibernate.jdbc.JDBCContext;
   42   import org.hibernate.cfg.Environment;
   43   import org.hibernate.util.NamingHelper;
   44   import org.hibernate.util.JTAHelper;
   45   
   46   /**
   47    * Factory for {@link JTATransaction} instances.
   48    * <p/>
   49    * To be completely accurate to the JTA spec, JTA implementations should
   50    * publish their contextual {@link UserTransaction} reference into JNDI.
   51    * However, in practice there are quite a few <tt>stand-alone</tt>
   52    * implementations intended for use outside of J2EE/JEE containers and
   53    * which therefore do not publish their {@link UserTransaction} references
   54    * into JNDI but which otherwise follow the aspects of the JTA specification.
   55    * This {@link TransactionFactory} implementation can support both models.
   56    * <p/>
   57    * For complete JTA implementations (including dependence on JNDI), the
   58    * {@link UserTransaction} reference is obtained by a call to
   59    * {@link #resolveInitialContext}.  Hibernate will then attempt to locate the
   60    * {@link UserTransaction} within this resolved
   61    * {@link InitialContext} based on the namespace returned by
   62    * {@link #resolveUserTransactionName}.
   63    * <p/>
   64    * For the so-called <tt>stand-alone</tt> implementations, we do not care at
   65    * all about the JNDI aspects just described.  Here, the implementation would
   66    * have a specific manner to obtain a reference to its contextual
   67    * {@link UserTransaction}; usually this would be a static code reference, but
   68    * again it varies.  Anyway, for each implementation the integration would need
   69    * to override the {@link #getUserTransaction} method and return the appropriate
   70    * thing.
   71    *
   72    * @author Gavin King
   73    * @author Steve Ebersole
   74    * @author Les Hazlewood
   75    */
   76   public class JTATransactionFactory implements TransactionFactory {
   77   	public static final String DEFAULT_USER_TRANSACTION_NAME = "java:comp/UserTransaction";
   78   	private static final Logger log = LoggerFactory.getLogger( JTATransactionFactory.class );
   79   
   80   	protected InitialContext initialContext;
   81   	protected String userTransactionName;
   82   
   83   	/**
   84   	 * Configure this transaction factory.  Specifically here we are attempting to
   85   	 * resolve both an {@link #getInitialContext InitialContext} as well as the
   86   	 * {@link #getUserTransactionName() JNDI namespace} for the {@link UserTransaction}.
   87   	 *
   88   	 * @param props The configuration properties
   89   	 *
   90   	 * @exception HibernateException
   91   	 */
   92   	public void configure(Properties props) throws HibernateException {
   93   		this.initialContext = resolveInitialContext( props );
   94   		this.userTransactionName = resolveUserTransactionName( props );
   95   		log.trace( "Configured JTATransactionFactory to use [{}] for UserTransaction JDNI namespace", userTransactionName );
   96   	}
   97   
   98   	/**
   99   	 * Given the lot of Hibernate configuration properties, resolve appropriate
  100   	 * reference to JNDI {@link InitialContext}.
  101   	 * <p/>
  102   	 * In general, the properties in which we are interested here all begin with
  103   	 * <tt>hibernate.jndi</tt>.  Especially important depending on your
  104   	 * environment are {@link Environment#JNDI_URL hibernate.jndi.url} and
  105   	 *  {@link Environment#JNDI_CLASS hibernate.jndi.class}
  106   	 *
  107   	 * @param properties The Hibernate config properties.
  108   	 * @return The resolved InitialContext.
  109   	 */
  110   	protected final InitialContext resolveInitialContext(Properties properties) {
  111   		try {
  112   			return NamingHelper.getInitialContext( properties );
  113   		}
  114   		catch ( NamingException ne ) {
  115   			throw new HibernateException( "Could not obtain initial context", ne );
  116   		}
  117   	}
  118   
  119   	/**
  120   	 * Given the lot of Hibernate configuration properties, resolve appropriate
  121   	 * JNDI namespace to use for {@link UserTransaction} resolution.
  122   	 * <p/>
  123   	 * We determine the namespace to use by<ol>
  124   	 * <li>Any specified {@link Environment#USER_TRANSACTION jta.UserTransaction} config property</li>
  125   	 * <li>If a {@link TransactionManagerLookup} was indicated, use its
  126   	 * {@link TransactionManagerLookup#getUserTransactionName}</li>
  127   	 * <li>finally, as a last resort, we use {@link #DEFAULT_USER_TRANSACTION_NAME}</li>
  128   	 * </ol>
  129   	 *
  130   	 * @param properties The Hibernate config properties.
  131   	 * @return The resolved {@link UserTransaction} namespace
  132   	 */
  133   	protected final String resolveUserTransactionName(Properties properties) {
  134   		String utName = properties.getProperty( Environment.USER_TRANSACTION );
  135   		if ( utName == null ) {
  136   			TransactionManagerLookup lookup = TransactionManagerLookupFactory.getTransactionManagerLookup( properties );
  137   			if ( lookup != null ) {
  138   				utName = lookup.getUserTransactionName();
  139   			}
  140   		}
  141   		return utName == null ? DEFAULT_USER_TRANSACTION_NAME : utName;
  142   	}
  143   
  144   	/**
  145   	 * {@inheritDoc}
  146   	 */
  147   	public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)
  148   			throws HibernateException {
  149   		UserTransaction ut = getUserTransaction();
  150   		return new JTATransaction( ut, jdbcContext, transactionContext );
  151   	}
  152   
  153   	/**
  154   	 * Get the {@link UserTransaction} reference.
  155   	 *
  156   	 * @return The appropriate {@link UserTransaction} reference.
  157   	 */
  158   	protected UserTransaction getUserTransaction() {
  159   		log.trace( "Attempting to locate UserTransaction via JNDI [{}]", getUserTransactionName() );
  160   
  161   		try {
  162   			UserTransaction ut = ( UserTransaction ) getInitialContext().lookup( getUserTransactionName() );
  163   			if ( ut == null ) {
  164   				throw new TransactionException( "Naming service lookup for UserTransaction returned null [" + getUserTransactionName() +"]" );
  165   			}
  166   
  167   			log.trace( "Obtained UserTransaction" );
  168   
  169   			return ut;
  170   		}
  171   		catch ( NamingException ne ) {
  172   			throw new TransactionException( "Could not find UserTransaction in JNDI [" + getUserTransaction() + "]", ne );
  173   		}
  174   	}
  175   
  176   	/**
  177   	 * Getter for property 'initialContext'.
  178   	 *
  179   	 * @return Value for property 'initialContext'.
  180   	 */
  181   	protected InitialContext getInitialContext() {
  182   		return initialContext;
  183   	}
  184   
  185   	/**
  186   	 * Getter for property 'userTransactionName'.
  187   	 * The algorithm here is
  188   	 *
  189   	 * @return Value for property 'userTransactionName'.
  190   	 */
  191   	protected String getUserTransactionName() {
  192   		return userTransactionName;
  193   	}
  194   
  195   	/**
  196   	 * {@inheritDoc}
  197   	 */
  198   	public ConnectionReleaseMode getDefaultReleaseMode() {
  199   		return ConnectionReleaseMode.AFTER_STATEMENT;
  200   	}
  201   
  202   	/**
  203   	 * {@inheritDoc}
  204   	 */
  205   	public boolean isTransactionManagerRequired() {
  206   		return false;
  207   	}
  208   
  209   	/**
  210   	 * {@inheritDoc}
  211   	 */
  212   	public boolean areCallbacksLocalToHibernateTransactions() {
  213   		return false;
  214   	}
  215   
  216   	/**
  217   	 * {@inheritDoc}
  218   	 */
  219   	public boolean isTransactionInProgress(
  220   			JDBCContext jdbcContext,
  221   			Context transactionContext,
  222   			Transaction transaction) {
  223   		try {
  224   			// Essentially:
  225   			// 1) If we have a local (Hibernate) transaction in progress
  226   			//      and it already has the UserTransaction cached, use that
  227   			//      UserTransaction to determine the status.
  228   			// 2) If a transaction manager has been located, use
  229   			//      that transaction manager to determine the status.
  230   			// 3) Finally, as the last resort, try to lookup the
  231   			//      UserTransaction via JNDI and use that to determine the
  232   			//      status.
  233   			if ( transaction != null ) {
  234   				UserTransaction ut = ( ( JTATransaction ) transaction ).getUserTransaction();
  235   				if ( ut != null ) {
  236   					return JTAHelper.isInProgress( ut.getStatus() );
  237   				}
  238   			}
  239   
  240   			if ( jdbcContext.getFactory().getTransactionManager() != null ) {
  241   				return JTAHelper.isInProgress( jdbcContext.getFactory().getTransactionManager().getStatus() );
  242   			}
  243   			else {
  244   				UserTransaction ut = getUserTransaction();
  245   				return ut != null && JTAHelper.isInProgress( ut.getStatus() );
  246   			}
  247   		}
  248   		catch ( SystemException se ) {
  249   			throw new TransactionException( "Unable to check transaction status", se );
  250   		}
  251   	}
  252   
  253   }

Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » transaction » [javadoc | source]