001: /*
002: * Helma License Notice
003: *
004: * The contents of this file are subject to the Helma License
005: * Version 2.0 (the "License"). You may not use this file except in
006: * compliance with the License. A copy of the License is available at
007: * http://adele.helma.org/download/helma/license.txt
008: *
009: * Copyright 1998-2003 Helma Software. All Rights Reserved.
010: *
011: * $RCSfile$
012: * $Author: hannes $
013: * $Revision: 8686 $
014: * $Date: 2007-12-06 21:13:59 +0100 (Don, 06 Dez 2007) $
015: */
016: package helma.framework.core;
017:
018: import helma.objectmodel.INode;
019: import helma.objectmodel.db.Node;
020: import helma.objectmodel.db.NodeHandle;
021: import helma.scripting.ScriptingEngine;
022:
023: import java.util.*;
024: import java.io.*;
025:
026: public class SessionManager {
027:
028: protected Hashtable sessions;
029:
030: protected Application app;
031:
032: public SessionManager() {
033: sessions = new Hashtable();
034: }
035:
036: public void init(Application app) {
037: this .app = app;
038: }
039:
040: public void shutdown() {
041: sessions.clear();
042: }
043:
044: public Session createSession(String sessionId) {
045: Session session = getSession(sessionId);
046:
047: if (session == null) {
048: session = new Session(sessionId, app);
049: sessions.put(sessionId, session);
050: }
051:
052: return session;
053: }
054:
055: public Session getSession(String sessionId) {
056: if (sessionId == null)
057: return null;
058:
059: return (Session) sessions.get(sessionId);
060: }
061:
062: /**
063: * Return the whole session map. We return a clone of the table to prevent
064: * actual changes from the table itself, which is managed by the application.
065: * It is safe and allowed to manipulate the session objects contained in the table, though.
066: */
067: public Map getSessions() {
068: return (Map) sessions.clone();
069: }
070:
071: /**
072: * Returns the number of currenty active sessions.
073: */
074: public int countSessions() {
075: return sessions.size();
076: }
077:
078: /**
079: * Remove the session from the sessions-table and logout the user.
080: */
081: public void discardSession(Session session) {
082: session.logout();
083: sessions.remove(session.getSessionId());
084: }
085:
086: /**
087: * Log in a user given his or her user name and password.
088: * @deprecated
089: */
090: public boolean loginSession(String uname, String password,
091: Session session) {
092: return app.loginSession(uname, password, session);
093: }
094:
095: /**
096: * Log out a session from this application.
097: * @deprecated
098: */
099: public void logoutSession(Session session) {
100: app.logoutSession(session);
101: }
102:
103: /**
104: * Return an array of <code>SessionBean</code> objects currently associated with a given
105: * Helma user.
106: */
107: public List getSessionsForUsername(String username) {
108: ArrayList list = new ArrayList();
109:
110: if (username == null) {
111: return list;
112: }
113:
114: Enumeration e = sessions.elements();
115: while (e.hasMoreElements()) {
116: Session s = (Session) e.nextElement();
117:
118: if (s != null && username.equals(s.getUID())) {
119: // append to list if session is logged in and fits the given username
120: list.add(new SessionBean(s));
121: }
122: }
123:
124: return list;
125: }
126:
127: /**
128: * Return a list of Helma nodes (HopObjects - the database object representing the user,
129: * not the session object) representing currently logged in users.
130: */
131: public List getActiveUsers() {
132: ArrayList list = new ArrayList();
133:
134: for (Enumeration e = sessions.elements(); e.hasMoreElements();) {
135: Session s = (Session) e.nextElement();
136:
137: if (s != null && s.isLoggedIn()) {
138: // returns a session if it is logged in and has not been
139: // returned before (so for each logged-in user is only added once)
140: INode node = s.getUserNode();
141:
142: // we check again because user may have been logged out between the first check
143: if (node != null && !list.contains(node)) {
144: list.add(node);
145: }
146: }
147: }
148:
149: return list;
150: }
151:
152: /**
153: * Dump session state to a file.
154: *
155: * @param f the file to write session into, or null to use the default sesssion store.
156: */
157: public void storeSessionData(File f, ScriptingEngine engine) {
158: if (f == null) {
159: f = new File(app.dbDir, "sessions");
160: }
161:
162: try {
163: OutputStream ostream = new BufferedOutputStream(
164: new FileOutputStream(f));
165: ObjectOutputStream p = new ObjectOutputStream(ostream);
166:
167: synchronized (sessions) {
168: p.writeInt(sessions.size());
169:
170: for (Enumeration e = sessions.elements(); e
171: .hasMoreElements();) {
172: try {
173: engine.serialize(e.nextElement(), p);
174: // p.writeObject(e.nextElement());
175: } catch (NotSerializableException nsx) {
176: // not serializable, skip this session
177: app.logError("Error serializing session.", nsx);
178: }
179: }
180: }
181:
182: p.flush();
183: ostream.close();
184: app.logEvent("stored " + sessions.size()
185: + " sessions in file");
186: } catch (Exception e) {
187: app.logError("error storing session data.", e);
188: }
189: }
190:
191: /**
192: * loads the serialized session table from a given file or from dbdir/sessions
193: */
194: public void loadSessionData(File f, ScriptingEngine engine) {
195: if (f == null) {
196: f = new File(app.dbDir, "sessions");
197: }
198:
199: // compute session timeout value
200: int sessionTimeout = 30;
201:
202: try {
203: sessionTimeout = Math.max(0, Integer.parseInt(app
204: .getProperty("sessionTimeout", "30")));
205: } catch (Exception ignore) {
206: System.out.println(ignore.toString());
207: }
208:
209: long now = System.currentTimeMillis();
210:
211: try {
212: // load the stored data:
213: InputStream istream = new BufferedInputStream(
214: new FileInputStream(f));
215: ObjectInputStream p = new ObjectInputStream(istream);
216: int size = p.readInt();
217: int ct = 0;
218: Hashtable newSessions = new Hashtable();
219:
220: while (ct < size) {
221: Session session = (Session) engine.deserialize(p);
222:
223: if ((now - session.lastTouched()) < (sessionTimeout * 60000)) {
224: session.setApp(app);
225: newSessions.put(session.getSessionId(), session);
226: }
227:
228: ct++;
229: }
230:
231: p.close();
232: istream.close();
233: sessions = newSessions;
234: app.logEvent("loaded " + newSessions.size()
235: + " sessions from file");
236: } catch (FileNotFoundException fnf) {
237: // suppress error message if session file doesn't exist
238: } catch (Exception e) {
239: app.logError("error loading session data.", e);
240: }
241: }
242:
243: /**
244: * Purge sessions that have not been used for a certain amount of time.
245: * This is called by run().
246: *
247: * @param lastSessionCleanup the last time sessions were purged
248: * @return the updated lastSessionCleanup value
249: */
250: protected long cleanupSessions(long lastSessionCleanup) {
251:
252: long now = System.currentTimeMillis();
253: long sessionCleanupInterval = 60000;
254:
255: // check if we should clean up user sessions
256: if ((now - lastSessionCleanup) > sessionCleanupInterval) {
257:
258: // get session timeout
259: int sessionTimeout = 30;
260:
261: try {
262: sessionTimeout = Math.max(0, Integer.parseInt(app
263: .getProperty("sessionTimeout", "30")));
264: } catch (NumberFormatException nfe) {
265: app.logEvent("Invalid sessionTimeout setting: "
266: + app.getProperty("sessionTimeout"));
267: }
268:
269: RequestEvaluator this Evaluator = null;
270:
271: try {
272:
273: this Evaluator = app.getEvaluator();
274:
275: Session[] sessionArray = (Session[]) sessions.values()
276: .toArray(new Session[0]);
277:
278: for (int i = 0; i < sessionArray.length; i++) {
279: Session session = sessionArray[i];
280:
281: session.pruneUploads();
282: if ((now - session.lastTouched()) > (sessionTimeout * 60000)) {
283: NodeHandle userhandle = session.userHandle;
284:
285: if (userhandle != null) {
286: try {
287: Object[] param = { session
288: .getSessionId() };
289:
290: this Evaluator.invokeInternal(
291: userhandle, "onLogout", param);
292: } catch (Exception x) {
293: // errors should already be logged by requestevaluator, but you never know
294: app.logError("Error in onLogout", x);
295: }
296: }
297:
298: discardSession(session);
299: }
300: }
301: } catch (Exception cx) {
302: app.logError("Error cleaning up sessions", cx);
303: } finally {
304: if (thisEvaluator != null) {
305: app.releaseEvaluator(thisEvaluator);
306: }
307: }
308: return now;
309: } else {
310: return lastSessionCleanup;
311: }
312: }
313:
314: }
|