FileDocCategorySizeDatePackage
ThreadLocalSessionContext.javaAPI DocHibernate 3.2.511534Wed Jan 25 22:22:52 GMT 2006org.hibernate.context

ThreadLocalSessionContext

public class ThreadLocalSessionContext extends Object implements CurrentSessionContext
A {@link CurrentSessionContext} impl which scopes the notion of current session by the current thread of execution. Unlike the JTA counterpart, threads do not give us a nice hook to perform any type of cleanup making it questionable for this impl to actually generate Session instances. In the interest of usability, it was decided to have this default impl actually generate a session upon first request and then clean it up after the {@link org.hibernate.Transaction} associated with that session is committed/rolled-back. In order for ensuring that happens, the sessions generated here are unusable until after {@link Session#beginTransaction()} has been called. If close() is called on a session managed by this class, it will be automatically unbound.

Additionally, the static {@link #bind} and {@link #unbind} methods are provided to allow application code to explicitly control opening and closing of these sessions. This, with some from of interception, is the preferred approach. It also allows easy framework integration and one possible approach for implementing long-sessions.

The {@link #buildOrObtainSession}, {@link #isAutoCloseEnabled}, {@link #isAutoFlushEnabled}, {@link #getConnectionReleaseMode}, and {@link #buildCleanupSynch} methods are all provided to allow easy subclassing (for long- running session scenarios, for example).

author
Steve Ebersole

Fields Summary
private static final Log
log
private static final Class[]
SESS_PROXY_INTERFACES
private static final ThreadLocal
context
A ThreadLocal maintaining current sessions for the given execution thread. The actual ThreadLocal variable is a java.util.Map to account for the possibility for multiple SessionFactorys being used during execution of the given thread.
protected final org.hibernate.engine.SessionFactoryImplementor
factory
Constructors Summary
public ThreadLocalSessionContext(org.hibernate.engine.SessionFactoryImplementor factory)


	   
		this.factory = factory;
	
Methods Summary
public static voidbind(org.hibernate.Session session)
Associates the given session with the current thread of execution.

param
session The session to bind.

		SessionFactory factory = session.getSessionFactory();
		cleanupAnyOrphanedSession( factory );
		doBind( session, factory );
	
protected org.hibernate.context.ThreadLocalSessionContext$CleanupSynchbuildCleanupSynch()

		return new CleanupSynch( factory );
	
protected org.hibernate.classic.SessionbuildOrObtainSession()
Strictly provided for subclassing purposes; specifically to allow long-session support.

This implementation always just opens a new session.

return
the built or (re)obtained session.

		return factory.openSession(
				null,
		        isAutoFlushEnabled(),
		        isAutoCloseEnabled(),
		        getConnectionReleaseMode()
			);
	
private static voidcleanupAnyOrphanedSession(org.hibernate.SessionFactory factory)

		Session orphan = doUnbind( factory, false );
		if ( orphan != null ) {
			log.warn( "Already session bound on call to bind(); make sure you clean up your sessions!" );
			try {
				if ( orphan.getTransaction() != null && orphan.getTransaction().isActive() ) {
					try {
						orphan.getTransaction().rollback();
					}
					catch( Throwable t ) {
						log.debug( "Unable to rollback transaction for orphaned session", t );
					}
				}
				orphan.close();
			}
			catch( Throwable t ) {
				log.debug( "Unable to close orphaned session", t );
			}
		}
	
public final org.hibernate.classic.SessioncurrentSession()

		Session current = existingSession( factory );
		if (current == null) {
			current = buildOrObtainSession();
			// register a cleanup synch
			current.getTransaction().registerSynchronization( buildCleanupSynch() );
			// wrap the session in the transaction-protection proxy
			if ( needsWrapping( current ) ) {
				current = wrap( current );
			}
			// then bind it
			doBind( current, factory );
		}
		return current;
	
private static voiddoBind(org.hibernate.Session session, org.hibernate.SessionFactory factory)

		Map sessionMap = sessionMap();
		if ( sessionMap == null ) {
			sessionMap = new HashMap();
			context.set( sessionMap );
		}
		sessionMap.put( factory, session );
	
private static org.hibernate.classic.SessiondoUnbind(org.hibernate.SessionFactory factory, boolean releaseMapIfEmpty)

		Map sessionMap = sessionMap();
		Session session = null;
		if ( sessionMap != null ) {
			session = ( Session ) sessionMap.remove( factory );
			if ( releaseMapIfEmpty && sessionMap.isEmpty() ) {
				context.set( null );
			}
		}
		return session;
	
private static org.hibernate.classic.SessionexistingSession(org.hibernate.SessionFactory factory)

		Map sessionMap = sessionMap();
		if ( sessionMap == null ) {
			return null;
		}
		else {
			return ( Session ) sessionMap.get( factory );
		}
	
protected org.hibernate.ConnectionReleaseModegetConnectionReleaseMode()
Mainly for subclass usage. This impl always returns after_transaction.

return
The connection release mode for any built sessions.

		return factory.getSettings().getConnectionReleaseMode();
	
protected org.hibernate.engine.SessionFactoryImplementorgetFactory()

		return factory;
	
protected booleanisAutoCloseEnabled()
Mainly for subclass usage. This impl always returns true.

return
Whether or not the the session should be closed by transaction completion.

		return true;
	
protected booleanisAutoFlushEnabled()
Mainly for subclass usage. This impl always returns true.

return
Whether or not the the session should be flushed prior transaction completion.

		return true;
	
private booleanneedsWrapping(org.hibernate.classic.Session session)

		// try to make sure we don't wrap and already wrapped session
		return session != null
		       && ! Proxy.isProxyClass( session.getClass() )
		       || ( Proxy.getInvocationHandler( session ) != null
		       && ! ( Proxy.getInvocationHandler( session ) instanceof TransactionProtectionWrapper ) );
	
protected static java.util.MapsessionMap()

		return ( Map ) context.get();
	
public static org.hibernate.classic.Sessionunbind(org.hibernate.SessionFactory factory)
Unassociate a previously bound session from the current thread of execution.

return
The session which was unbound.

		return doUnbind( factory, true );
	
protected org.hibernate.classic.Sessionwrap(org.hibernate.classic.Session session)

		TransactionProtectionWrapper wrapper = new TransactionProtectionWrapper( session );
		Session wrapped = ( Session ) Proxy.newProxyInstance(
				Session.class.getClassLoader(),
		        SESS_PROXY_INTERFACES,
		        wrapper
			);
		// yick!  need this for proper serialization/deserialization handling...
		wrapper.setWrapped( wrapped );
		return wrapped;