Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » context » [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.context;
   26   
   27   import org.hibernate.HibernateException;
   28   import org.hibernate.ConnectionReleaseMode;
   29   import org.hibernate.classic.Session;
   30   import org.hibernate.engine.SessionFactoryImplementor;
   31   import org.hibernate.util.JTAHelper;
   32   import org.slf4j.Logger;
   33   import org.slf4j.LoggerFactory;
   34   
   35   import javax.transaction.Transaction;
   36   import javax.transaction.TransactionManager;
   37   import javax.transaction.Synchronization;
   38   import java.util.Map;
   39   import java.util.Hashtable;
   40   
   41   /**
   42    * An implementation of {@link CurrentSessionContext} which scopes the notion
   43    * of a current session to a JTA transaction.  Because JTA gives us a nice
   44    * tie-in to clean up after ourselves, this implementation will generate
   45    * Sessions as needed provided a JTA transaction is in effect.  If a session
   46    * is not already associated with the current JTA transaction at the time
   47    * {@link #currentSession()} is called, a new session will be opened and it
   48    * will be associated with that JTA transaction.
   49    * <p/>
   50    * Note that the sessions returned from this method are automatically configured with
   51    * both the {@link org.hibernate.cfg.Environment#FLUSH_BEFORE_COMPLETION auto-flush} and
   52    * {@link org.hibernate.cfg.Environment#AUTO_CLOSE_SESSION auto-close} attributes set to
   53    * true, meaning that the Session will be automatically flushed and closed
   54    * as part of the lifecycle for the JTA transaction to which it is associated.
   55    * Additionally, it will also be configured to aggressively release JDBC
   56    * connections after each statement is executed.  These settings are governed
   57    * by the {@link #isAutoFlushEnabled()}, {@link #isAutoCloseEnabled()}, and
   58    * {@link #getConnectionReleaseMode()} methods; these are provided (along with
   59    * the {@link #buildOrObtainSession()} method) for easier subclassing for custom
   60    * JTA-based session tracking logic (like maybe long-session semantics).
   61    *
   62    * @author Steve Ebersole
   63    */
   64   public class JTASessionContext implements CurrentSessionContext {
   65   
   66   	private static final Logger log = LoggerFactory.getLogger( JTASessionContext.class );
   67   
   68   	protected final SessionFactoryImplementor factory;
   69   	private transient Map currentSessionMap = new Hashtable();
   70   
   71   	public JTASessionContext(SessionFactoryImplementor factory) {
   72   		this.factory = factory;
   73   	}
   74   
   75   	/**
   76   	 * {@inheritDoc}
   77   	 */
   78   	public Session currentSession() throws HibernateException {
   79   		TransactionManager transactionManager = factory.getTransactionManager();
   80   		if ( transactionManager == null ) {
   81   			throw new HibernateException( "No TransactionManagerLookup specified" );
   82   		}
   83   
   84   		Transaction txn;
   85   		try {
   86   			txn = transactionManager.getTransaction();
   87   			if ( txn == null ) {
   88   				throw new HibernateException( "Unable to locate current JTA transaction" );
   89   			}
   90   			if ( !JTAHelper.isInProgress( txn.getStatus() ) ) {
   91   				// We could register the session against the transaction even though it is
   92   				// not started, but we'd have no guarentee of ever getting the map
   93   				// entries cleaned up (aside from spawning threads).
   94   				throw new HibernateException( "Current transaction is not in progress" );
   95   			}
   96   		}
   97   		catch ( HibernateException e ) {
   98   			throw e;
   99   		}
  100   		catch ( Throwable t ) {
  101   			throw new HibernateException( "Problem locating/validating JTA transaction", t );
  102   		}
  103   
  104   		final Object txnIdentifier = factory.getSettings().getTransactionManagerLookup() == null
  105   				? txn
  106   				: factory.getSettings().getTransactionManagerLookup().getTransactionIdentifier( txn );
  107   
  108   		Session currentSession = ( Session ) currentSessionMap.get( txnIdentifier );
  109   
  110   		if ( currentSession == null ) {
  111   			currentSession = buildOrObtainSession();
  112   
  113   			try {
  114   				txn.registerSynchronization( buildCleanupSynch( txnIdentifier ) );
  115   			}
  116   			catch ( Throwable t ) {
  117   				try {
  118   					currentSession.close();
  119   				}
  120   				catch ( Throwable ignore ) {
  121   					log.debug( "Unable to release generated current-session on failed synch registration", ignore );
  122   				}
  123   				throw new HibernateException( "Unable to register cleanup Synchronization with TransactionManager" );
  124   			}
  125   
  126   			currentSessionMap.put( txnIdentifier, currentSession );
  127   		}
  128   
  129   		return currentSession;
  130   	}
  131   
  132   	/**
  133   	 * Builds a {@link CleanupSynch} capable of cleaning up the the current session map as an after transaction
  134   	 * callback.
  135   	 *
  136   	 * @param transactionIdentifier The transaction identifier under which the current session is registered.
  137   	 * @return The cleanup synch.
  138   	 */
  139   	private CleanupSynch buildCleanupSynch(Object transactionIdentifier) {
  140   		return new CleanupSynch( transactionIdentifier, this );
  141   	}
  142   
  143   	/**
  144   	 * Strictly provided for subclassing purposes; specifically to allow long-session
  145   	 * support.
  146   	 * <p/>
  147   	 * This implementation always just opens a new session.
  148   	 *
  149   	 * @return the built or (re)obtained session.
  150   	 */
  151   	protected Session buildOrObtainSession() {
  152   		return factory.openSession(
  153   				null,
  154   		        isAutoFlushEnabled(),
  155   		        isAutoCloseEnabled(),
  156   		        getConnectionReleaseMode()
  157   			);
  158   	}
  159   
  160   	/**
  161   	 * Mainly for subclass usage.  This impl always returns true.
  162   	 *
  163   	 * @return Whether or not the the session should be closed by transaction completion.
  164   	 */
  165   	protected boolean isAutoCloseEnabled() {
  166   		return true;
  167   	}
  168   
  169   	/**
  170   	 * Mainly for subclass usage.  This impl always returns true.
  171   	 *
  172   	 * @return Whether or not the the session should be flushed prior transaction completion.
  173   	 */
  174   	protected boolean isAutoFlushEnabled() {
  175   		return true;
  176   	}
  177   
  178   	/**
  179   	 * Mainly for subclass usage.  This impl always returns after_statement.
  180   	 *
  181   	 * @return The connection release mode for any built sessions.
  182   	 */
  183   	protected ConnectionReleaseMode getConnectionReleaseMode() {
  184   		return ConnectionReleaseMode.AFTER_STATEMENT;
  185   	}
  186   
  187   	/**
  188   	 * JTA transaction synch used for cleanup of the internal session map.
  189   	 */
  190   	protected static class CleanupSynch implements Synchronization {
  191   		private Object transactionIdentifier;
  192   		private JTASessionContext context;
  193   
  194   		public CleanupSynch(Object transactionIdentifier, JTASessionContext context) {
  195   			this.transactionIdentifier = transactionIdentifier;
  196   			this.context = context;
  197   		}
  198   
  199   		/**
  200   		 * {@inheritDoc}
  201   		 */
  202   		public void beforeCompletion() {
  203   		}
  204   
  205   		/**
  206   		 * {@inheritDoc}
  207   		 */
  208   		public void afterCompletion(int i) {
  209   			context.currentSessionMap.remove( transactionIdentifier );
  210   		}
  211   	}
  212   }

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