001: package org.hibernate.context;
002:
003: import org.hibernate.classic.Session;
004: import org.hibernate.HibernateException;
005: import org.hibernate.SessionFactory;
006: import org.hibernate.engine.SessionFactoryImplementor;
007:
008: import java.util.Map;
009: import java.util.HashMap;
010:
011: /**
012: * Represents a {@link CurrentSessionContext} the notion of a contextual session
013: * is managed by some external entity (generally some form of interceptor, etc).
014: * This external manager is responsible for scoping these contextual sessions
015: * appropriately binding/unbinding them here for exposure to the application
016: * through {@link SessionFactory#getCurrentSession} calls.
017: * <p/>
018: * Basically exposes two interfaces. <ul>
019: * <li>First is the implementation of CurrentSessionContext which is then used
020: * by the {@link SessionFactory#getCurrentSession()} calls. This
021: * portion is instance-based specific to the session factory owning the given
022: * instance of this impl (there will be one instance of this per each session
023: * factory using this strategy).
024: * <li>Second is the externally facing methods {@link #hasBind}, {@link #bind},
025: * and {@link #unbind} used by the external thing to manage exposure of the
026: * current session it is scoping. This portion is static to allow easy
027: * reference from that external thing.
028: * </ul>
029: * The underlying storage of the current sessions here is a static
030: * {@link ThreadLocal}-based map where the sessions are keyed by the
031: * the owning session factory.
032: *
033: * @author Steve Ebersole
034: */
035: public class ManagedSessionContext implements CurrentSessionContext {
036:
037: private static final ThreadLocal context = new ThreadLocal();
038: private final SessionFactoryImplementor factory;
039:
040: public ManagedSessionContext(SessionFactoryImplementor factory) {
041: this .factory = factory;
042: }
043:
044: /**
045: * @see CurrentSessionContext#currentSession
046: */
047: public Session currentSession() {
048: Session current = existingSession(factory);
049: if (current == null) {
050: throw new HibernateException(
051: "No session currently bound to execution context");
052: }
053: return current;
054: }
055:
056: /**
057: * Check to see if there is already a session associated with the current
058: * thread for the given session factory.
059: *
060: * @param factory The factory against which to check for a given session
061: * within the current thread.
062: * @return True if there is currently a session bound.
063: */
064: public static boolean hasBind(SessionFactory factory) {
065: return existingSession(factory) != null;
066: }
067:
068: /**
069: * Binds the given session to the current context for its session factory.
070: *
071: * @param session The session to be bound.
072: * @return Any previously bound session (should be null in most cases).
073: */
074: public static Session bind(Session session) {
075: return (Session) sessionMap(true).put(
076: session.getSessionFactory(), session);
077: }
078:
079: /**
080: * Unbinds the session (if one) current associated with the context for the
081: * given session.
082: *
083: * @param factory The factory for which to unbind the current session.
084: * @return The bound session if one, else null.
085: */
086: public static Session unbind(SessionFactory factory) {
087: Session existing = null;
088: Map sessionMap = sessionMap();
089: if (sessionMap != null) {
090: existing = (Session) sessionMap.remove(factory);
091: doCleanup();
092: }
093: return existing;
094: }
095:
096: private static Session existingSession(SessionFactory factory) {
097: Map sessionMap = sessionMap();
098: if (sessionMap == null) {
099: return null;
100: } else {
101: return (Session) sessionMap.get(factory);
102: }
103: }
104:
105: protected static Map sessionMap() {
106: return sessionMap(false);
107: }
108:
109: private static synchronized Map sessionMap(boolean createMap) {
110: Map sessionMap = (Map) context.get();
111: if (sessionMap == null && createMap) {
112: sessionMap = new HashMap();
113: context.set(sessionMap);
114: }
115: return sessionMap;
116: }
117:
118: private static synchronized void doCleanup() {
119: Map sessionMap = sessionMap(false);
120: if (sessionMap != null) {
121: if (sessionMap.isEmpty()) {
122: context.set(null);
123: }
124: }
125: }
126: }
|