001 /*
002 *
003 * $Revision: 14909 $ $Date: 2009-03-16 18:06:26 +0100 (Mon, 16 Mar 2009) $
004 *
005 * This file is part of *** M y C o R e ***
006 * See http://www.mycore.de/ for details.
007 *
008 * This program is free software; you can use it, redistribute it
009 * and / or modify it under the terms of the GNU General Public License
010 * (GPL) as published by the Free Software Foundation; either version 2
011 * of the License or (at your option) any later version.
012 *
013 * This program is distributed in the hope that it will be useful, but
014 * WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program, in a file called gpl.txt or license.txt.
020 * If not, write to the Free Software Foundation Inc.,
021 * 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
022 */
023
024 package org.mycore.common;
025
026 import static org.mycore.common.events.MCRSessionEvent.Type.created;
027 import static org.mycore.common.events.MCRSessionEvent.Type.destroyed;
028
029 import java.util.ArrayList;
030 import java.util.HashMap;
031 import java.util.List;
032 import java.util.Map;
033 import java.util.concurrent.locks.ReentrantReadWriteLock;
034
035 import org.mycore.common.events.MCRSessionListener;
036
037 /**
038 * Manages sessions for a MyCoRe system. This class is backed by a ThreadLocal
039 * variable, so every Thread is guaranteed to get a unique instance of
040 * MCRSession. Care must be taken when using an environment utilizing a Thread
041 * pool, such as many Servlet engines. In this case it is possible for the
042 * session object to stay attached to a thread where it should not be. Use the
043 * {@link #releaseCurrentSession()}method to reset the session object for a
044 * Thread to its default values.
045 *
046 * The basic idea for the implementation of this class is taken from an apache
047 * project, namely the class org.apache.common.latka.LatkaProperties.java
048 * written by Morgan Delagrange. Please see <http://www.apache.org/>.
049 *
050 * @author Detlev Degenhardt
051 * @author Thomas Scheffler (yagee)
052 * @version $Revision: 14909 $ $Date: 2009-03-16 18:06:26 +0100 (Mon, 16 Mar 2009) $
053 */
054 public class MCRSessionMgr {
055
056 private static Map<String, MCRSession> sessions = new HashMap<String, MCRSession>();
057
058 private static List<MCRSessionListener> listeners = new ArrayList<MCRSessionListener>();
059
060 private static ReentrantReadWriteLock listenersLock = new ReentrantReadWriteLock();
061
062 /**
063 * This ThreadLocal is automatically instantiated per thread with a MyCoRe
064 * session object containing the default session parameters which are set in
065 * the constructor of MCRSession.
066 *
067 * @see ThreadLocal
068 */
069 private static ThreadLocal<MCRSession> theThreadLocalSession = new ThreadLocal<MCRSession>() {
070 public MCRSession initialValue() {
071 return new MCRSession();
072 }
073 };
074
075 /**
076 * This method returns the unique MyCoRe session object for the current
077 * Thread. The session object is initialized with the default MyCoRe session
078 * data.
079 *
080 * @return MyCoRe MCRSession object
081 */
082 public static MCRSession getCurrentSession() {
083 return theThreadLocalSession.get();
084 }
085
086 /**
087 * This method sets a MyCoRe session object for the current Thread. This
088 * method fires a "activated" event, when called the first time for this
089 * session and thread.
090 *
091 * @see org.mycore.common.events.MCRSessionEvent.Type#activated
092 */
093 public static void setCurrentSession(MCRSession theSession) {
094 theSession.activate();
095 theThreadLocalSession.set(theSession);
096 }
097
098 /**
099 * Releases the MyCoRe session from its current thread. Subsequent calls of
100 * getCurrentSession() will return a different MCRSession object than before
101 * for the current Thread. One use for this method is to reset the session
102 * inside a Thread-pooling environment like Servlet engines. This method
103 * fires a "passivated" event, when called the last time for this session
104 * and thread.
105 *
106 * @see org.mycore.common.events.MCRSessionEvent.Type#passivated
107 */
108 public static void releaseCurrentSession() {
109 MCRSession session = theThreadLocalSession.get();
110 session.passivate();
111 MCRSession.LOGGER.debug("MCRSession released " + session.getID());
112 theThreadLocalSession.remove();
113 }
114
115 /**
116 * Returns the MCRSession for the given sessionID.
117 */
118 public static MCRSession getSession(String sessionID) {
119 MCRSession s = sessions.get(sessionID);
120 if (s == null) {
121 MCRSession.LOGGER.warn("MCRSession with ID " + sessionID + " not cached any more");
122 }
123 return s;
124 }
125
126 /**
127 * Add MCRSession to a static Map that manages all sessions. This method
128 * fires a "created" event and is invoked by MCRSession constructor.
129 *
130 * @see MCRSession#MCRSession()
131 * @see org.mycore.common.events.MCRSessionEvent.Type#created
132 */
133 static void addSession(MCRSession session) {
134 sessions.put(session.getID(), session);
135 session.fireSessionEvent(created, session.concurrentAccess.get());
136 }
137
138 /**
139 * Remove MCRSession from a static Map that manages all sessions. This
140 * method fires a "destroyed" event and is invoked by MCRSession.close().
141 *
142 * @see MCRSession#close()
143 * @see org.mycore.common.events.MCRSessionEvent.Type#destroyed
144 */
145 static void removeSession(MCRSession session) {
146 sessions.remove(session.getID());
147 session.fireSessionEvent(destroyed, session.concurrentAccess.get());
148 }
149
150 /**
151 * Add a MCRSessionListener, that gets infomed about MCRSessionEvents.
152 *
153 * @see #removeSessionListener(MCRSessionListener)
154 */
155 public static void addSessionListener(MCRSessionListener listener) {
156 listenersLock.writeLock().lock();
157 listeners.add(listener);
158 listenersLock.writeLock().unlock();
159 }
160
161 /**
162 * Removes a MCRSessionListener from the list.
163 *
164 * @see #addSessionListener(MCRSessionListener)
165 */
166 public static void removeSessionListener(MCRSessionListener listener) {
167 listenersLock.writeLock().lock();
168 listeners.remove(listener);
169 listenersLock.writeLock().unlock();
170 }
171
172 /**
173 * Allows access to all MCRSessionListener instances.
174 *
175 * Mainly for internal use of MCRSession.
176 */
177 static List<MCRSessionListener> getListeners() {
178 return listeners;
179 }
180
181 /**
182 * Allows to lock out access to list of MCESessionListener instances.
183 *
184 * When you want to read on the list, use the readLock() and use the
185 * writeLock() if you want to modify the list. Using locks will allow a high
186 * degree of concurrent access.
187 *
188 * Mainly for internal use of MCRSession.
189 *
190 * @see ReentrantReadWriteLock#readLock();
191 * @see ReentrantReadWriteLock#writeLock();
192 */
193 static ReentrantReadWriteLock getListenersLock() {
194 return listenersLock;
195 }
196
197 public static void close() {
198 listenersLock.writeLock().lock();
199 for (MCRSession session : sessions.values().toArray(new MCRSession[0])) {
200 session.close();
201 }
202 listenersLock.writeLock().unlock();
203 }
204
205 public static Map<String, MCRSession> getAllSessions() {
206 return sessions;
207 }
208
209 }