001: /*
002: * Copyright 2002-2005 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.orm.hibernate;
018:
019: import java.util.Collections;
020: import java.util.HashMap;
021: import java.util.Map;
022:
023: import net.sf.hibernate.FlushMode;
024: import net.sf.hibernate.Session;
025: import net.sf.hibernate.Transaction;
026:
027: import org.springframework.transaction.support.ResourceHolderSupport;
028: import org.springframework.util.Assert;
029:
030: /**
031: * Session holder, wrapping a Hibernate Session and a Hibernate Transaction.
032: * HibernateTransactionManager binds instances of this class
033: * to the thread, for a given SessionFactory.
034: *
035: * <p>Note: This is an SPI class, not intended to be used by applications.
036: *
037: * @author Juergen Hoeller
038: * @since 06.05.2003
039: * @see HibernateTransactionManager
040: * @see SessionFactoryUtils
041: */
042: public class SessionHolder extends ResourceHolderSupport {
043:
044: private static final Object DEFAULT_KEY = new Object();
045:
046: /**
047: * This Map needs to be synchronized because there might be multi-threaded
048: * access in the case of JTA with remote transaction propagation.
049: */
050: private final Map sessionMap = Collections
051: .synchronizedMap(new HashMap(1));
052:
053: private Transaction transaction;
054:
055: private FlushMode previousFlushMode;
056:
057: public SessionHolder(Session session) {
058: addSession(session);
059: }
060:
061: public SessionHolder(Object key, Session session) {
062: addSession(key, session);
063: }
064:
065: public Session getSession() {
066: return getSession(DEFAULT_KEY);
067: }
068:
069: public Session getSession(Object key) {
070: return (Session) this .sessionMap.get(key);
071: }
072:
073: public Session getValidatedSession() {
074: return getValidatedSession(DEFAULT_KEY);
075: }
076:
077: public Session getValidatedSession(Object key) {
078: Session session = (Session) this .sessionMap.get(key);
079: // Check for dangling Session that's around but already closed.
080: // Effectively an assertion: that should never happen in practice.
081: // We'll seamlessly remove the Session here, to not let it cause
082: // any side effects.
083: if (session != null && !session.isOpen()) {
084: this .sessionMap.remove(key);
085: session = null;
086: }
087: return session;
088: }
089:
090: public Session getAnySession() {
091: synchronized (this .sessionMap) {
092: if (!this .sessionMap.isEmpty()) {
093: return (Session) this .sessionMap.values().iterator()
094: .next();
095: }
096: return null;
097: }
098: }
099:
100: public void addSession(Session session) {
101: addSession(DEFAULT_KEY, session);
102: }
103:
104: public void addSession(Object key, Session session) {
105: Assert.notNull(key, "Key must not be null");
106: Assert.notNull(session, "Session must not be null");
107: this .sessionMap.put(key, session);
108: }
109:
110: public Session removeSession(Object key) {
111: return (Session) this .sessionMap.remove(key);
112: }
113:
114: public boolean containsSession(Session session) {
115: return this .sessionMap.containsValue(session);
116: }
117:
118: public boolean isEmpty() {
119: return this .sessionMap.isEmpty();
120: }
121:
122: public boolean doesNotHoldNonDefaultSession() {
123: synchronized (this .sessionMap) {
124: return this .sessionMap.isEmpty()
125: || (this .sessionMap.size() == 1 && this .sessionMap
126: .containsKey(DEFAULT_KEY));
127: }
128: }
129:
130: public void setTransaction(Transaction transaction) {
131: this .transaction = transaction;
132: }
133:
134: public Transaction getTransaction() {
135: return transaction;
136: }
137:
138: public void setPreviousFlushMode(FlushMode previousFlushMode) {
139: this .previousFlushMode = previousFlushMode;
140: }
141:
142: public FlushMode getPreviousFlushMode() {
143: return previousFlushMode;
144: }
145:
146: public void clear() {
147: super.clear();
148: this.transaction = null;
149: this.previousFlushMode = null;
150: }
151:
152: }
|