001: /*
002: * Enhydra Java Application Server Project
003: *
004: * The contents of this file are subject to the Enhydra Public License
005: * Version 1.1 (the "License"); you may not use this file except in
006: * compliance with the License. You may obtain a copy of the License on
007: * the Enhydra web site ( http://www.enhydra.org/ ).
008: *
009: * Software distributed under the License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
011: * the License for the specific terms governing rights and limitations
012: * under the License.
013: *
014: * The Initial Developer of the Enhydra Application Server is Lutris
015: * Technologies, Inc. The Enhydra Application Server and portions created
016: * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
017: * All Rights Reserved.
018: *
019: * Contributor(s):
020: *
021: * $Id: PersistentSessionHome.java,v 1.2 2006-06-15 13:44:07 sinisa Exp $
022: */
023:
024: package com.lutris.appserver.server.sessionEnhydra.persistent;
025:
026: import java.util.Enumeration;
027:
028: import com.lutris.appserver.server.Enhydra;
029: import com.lutris.appserver.server.session.SessionException;
030: import com.lutris.appserver.server.sessionEnhydra.PagedSession;
031: import com.lutris.appserver.server.sessionEnhydra.PagedSessionHome;
032: import com.lutris.appserver.server.sessionEnhydra.StandardSessionManager;
033: import com.lutris.logging.Logger;
034: import com.lutris.util.Config;
035: import com.lutris.util.ConfigException;
036:
037: /**
038: * PersistentSessionHome writes all passive sessions
039: * to a database. The sessions are written by serializing
040: * all the data (excluding the session manager) that is
041: * associated with a session. This requires that
042: * the session data and user associated with a session
043: * are serializable. PersistentSessionHome
044: * should be used by applications that want failover support
045: * or that want to run in a clustered environment.<p>
046: *
047: * The session data is written to a table in the database
048: * that is defined as (Informix):<p>
049: *
050: * <pre>
051: * CREATE TABLE PersistentSession
052: * (
053: * sessionKey VARCHAR(64) NOT NULL,
054: * isNew CHAR(1) DEFAULT "1" NOT NULL,
055: * timeCreated DECIMAL(19,0),
056: * timeLastUsed DECIMAL(19,0),
057: * timeExpires DECIMAL(19,0),
058: * maxIdleTime DECIMAL(19,0),
059: * maxNoUserIdleTime INTEGER,
060: * userName VARCHAR(255),
061: * data BYTE,
062: * PRIMARY KEY(sessionKey)
063: * )
064: * </pre>
065: *
066: * The configuration settings for PersistentSessionHome:<p>
067: *
068: * <ul>
069: *
070: * <li><code>DatabaseName: {String}</code><p>
071: * The database that will be accessed. This session is optional. If
072: * not set then the default database is accessed.
073: *
074: * <li><code>DBTableName: {String}</code><p>
075: * The name of the table in the database where session data
076: * will be written. The default table name is "PersistentSession".<p>
077: *
078: * </ul>
079: *
080: * @see StandardSessionManager
081: * @version $Revision: 1.2 $
082: * @author Kyle Clark
083: */
084: public class PersistentSessionHome extends PagedSessionHome {
085:
086: /**
087: * The name of the database that will be accessed.
088: */
089: static String dbName = null;
090:
091: /**
092: * The name of the database table where session information
093: * will be stored.
094: */
095: static String dbTableName = "PersistentSession"; // Default
096:
097: /**
098: * Configuration keys.
099: */
100: private static final String DB_NAME_KEY = "DatabaseName";
101: private static final String DB_TABLE_NAME_KEY = "DBTableName";
102:
103: /**
104: * @param sessionMgr
105: * The session manager associated with this session home.
106: * @param config
107: * Object parsed from configuration file. This should be
108: * for the section containing the standard session home configuration.
109: * @param loader
110: * The class load to use when load objects from persistent store.
111: * @exception ConfigException
112: * signifies a problem in the configuration file.
113: * @exception SessionException
114: * if the initialization fails.
115: */
116: public PersistentSessionHome(StandardSessionManager sessionMgr,
117: Config config, ClassLoader loader) throws SessionException,
118: ConfigException {
119: super (sessionMgr, config, loader);
120: if (config.containsKey(DB_TABLE_NAME_KEY)) {
121: dbTableName = config.getString(DB_TABLE_NAME_KEY);
122: }
123: debug(DB_TABLE_NAME_KEY + " = " + dbTableName);
124: dbName = getDatabaseName(config);
125: if (dbName != null) {
126: debug(DB_NAME_KEY + " = " + dbName);
127: } else {
128: debug(DB_NAME_KEY + " = DEFAULT");
129: }
130: }
131:
132: /**
133: * Returns the name of the database being accessed by this manager.
134: *
135: * @return the database name. May be null if the default database is
136: * being accessed.
137: */
138: public String getDatabaseName() {
139: return dbName;
140: }
141:
142: /**
143: * Returns the name of the database that should be accessed.
144: *
145: * @param config the config in whihc to look up the database
146: * setting.
147: * @return the database name. May be null if the default database is
148: * being accessed.
149: * @exception ConfigException if an error occurs.
150: */
151: public static String getDatabaseName(Config config)
152: throws ConfigException {
153: String s = null;
154: if (config.containsKey(DB_NAME_KEY)) {
155: s = config.getString(DB_NAME_KEY);
156: if (s.length() == 0) {
157: s = null;
158: }
159: }
160: return s;
161: }
162:
163: /**
164: * Creates a new session object. This method is intended to be
165: * overriden by classes that extend PagedSessionHome.
166: *
167: * @return a new session.
168: */
169: protected PagedSession newSession(StandardSessionManager mgr,
170: String sessionKey) throws SessionException {
171: PersistentSession session = new PersistentSession(mgr,
172: sessionKey, this );
173: DBUtil.dbInsert(session, dbName);
174: return session;
175: }
176:
177: /**
178: * Deletes a paged session. If the session doesn't exist then this
179: * is a noop.
180: *
181: * @param sessionKey the key identifying the session
182: * that should be deleted.
183: */
184: protected void deleteSession(String sessionKey)
185: throws SessionException {
186: // Delete from database
187: DBUtil.dbDelete(sessionKey, dbName);
188: }
189:
190: /**
191: * Pages a session to disk.
192: *
193: * @param session the session to page.
194: * @exception SessionException if the paged session could not be
195: * paged out.
196: */
197: protected synchronized void pageOut(PagedSession s)
198: throws SessionException {
199: // N.B. it is possible for the session to be removed
200: // from the database if running in a clustered environment.
201: // The idle timer in another application instance may run
202: // while this session is in the active state.
203: // If it was removed then the update would fail and we
204: // need to re-insert.
205: if (DBUtil.dbUpdate((PersistentSession) s, dbName) <= 0) {
206: DBUtil.dbInsert((PersistentSession) s, dbName);
207: }
208: }
209:
210: /**
211: * Reads a paged session from disk.
212: *
213: * @param sessionKey the key identifying the session that should
214: * be paged in.
215: * @return the paged session that was read in.
216: * @exception SessionException if the paged session could not be
217: * read in or does not exist.
218: */
219: protected synchronized PagedSession pageIn(String sessionKey)
220: throws SessionException {
221: SessionQuery sessionQuery = new SessionQuery(sessionKey, loader);
222: PersistentSession s = (PersistentSession) DBUtil.dbQuery(
223: sessionQuery, dbName);
224: if (s != null) {
225: s.restoreSessionHome(this );
226: s.restoreSessionManager(sessionMgr);
227: }
228: return s;
229: }
230:
231: /**
232: * Returns the number of paged sessions.
233: */
234: protected synchronized int getPagedSessionCount()
235: throws SessionException {
236: SizeQuery sizeQuery = new SizeQuery();
237: Integer size = (Integer) DBUtil.dbQuery(sizeQuery, dbName);
238: return size.intValue();
239: }
240:
241: /**
242: * Returns true if the specified session key is in use
243: * by a session that has been paged out.
244: *
245: * @param sessionKey the session key to test.
246: * @return true if the session key is in use by a paged session.
247: */
248: protected boolean pagedSessionKeyExists(String sessionKey)
249: throws SessionException {
250: KeyExistsQuery keyExistsQuery = new KeyExistsQuery(sessionKey);
251: Boolean exists = (Boolean) DBUtil.dbQuery(keyExistsQuery,
252: dbName);
253: return exists.booleanValue();
254: }
255:
256: /**
257: * Returns an enumeration of the keys of all the sessions that have
258: * been paged out to persistent storage.
259: *
260: * @return the session key enumeration.
261: * @exception SessionException if an error occurs.
262: */
263: protected Enumeration getPagedSessionKeys() throws SessionException {
264: return (Enumeration) DBUtil.dbQuery(new KeysQuery(), dbName);
265: }
266:
267: /**
268: * Removes a session that is new and paged.
269: *
270: * @exception SessionException if an error occurs.
271: */
272: protected boolean cleanupNewPagedSession() throws SessionException {
273: String key = null;
274: UnusedQuery unusedQuery = new UnusedQuery();
275: key = (String) DBUtil.dbQuery(unusedQuery, dbName);
276: if (key != null) {
277: removeSession(key);
278: return true;
279: }
280: return false;
281: }
282:
283: /**
284: * Shuts dows the session home.
285: */
286: public void shutdown() {
287: // TODO
288: }
289:
290: /**
291: * Prints debug information under Logger.DEBUG.
292: *
293: * @param msg the message to print.
294: */
295: protected void debug(String msg) {
296: debug(0, msg);
297: }
298:
299: /**
300: * Prints debug information under Logger.DEBUG.
301: *
302: * @param level the debug level.
303: * @param msg the message to print.
304: */
305: protected void debug(int level, String msg) {
306: int dbg = Logger.DEBUG;
307: switch (level) {
308: case 1:
309: dbg = Logger.DEBUG1;
310: break;
311: case 2:
312: dbg = Logger.DEBUG2;
313: break;
314: case 3:
315: dbg = Logger.DEBUG3;
316: break;
317: case 4:
318: dbg = Logger.DEBUG4;
319: break;
320: case 5:
321: dbg = Logger.DEBUG5;
322: break;
323: case 6:
324: dbg = Logger.DEBUG6;
325: break;
326: case 7:
327: dbg = Logger.DEBUG7;
328: break;
329: case 8:
330: dbg = Logger.DEBUG8;
331: break;
332: case 9:
333: dbg = Logger.DEBUG9;
334: break;
335: default:
336: dbg = Logger.DEBUG;
337: break;
338: }
339: Enhydra.getLogChannel().write(
340: dbg,
341: "PersistentSessionHome("
342: + Thread.currentThread().getName() + "): "
343: + msg);
344: }
345: }
|