0001: /*
0002: * Enhydra Java Application Server Project
0003: *
0004: * The contents of this file are subject to the Enhydra Public License
0005: * Version 1.1 (the "License"); you may not use this file except in
0006: * compliance with the License. You may obtain a copy of the License on
0007: * the Enhydra web site ( http://www.enhydra.org/ ).
0008: *
0009: * Software distributed under the License is distributed on an "AS IS"
0010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
0011: * the License for the specific terms governing rights and limitations
0012: * under the License.
0013: *
0014: * The Initial Developer of the Enhydra Application Server is Lutris
0015: * Technologies, Inc. The Enhydra Application Server and portions created
0016: * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
0017: * All Rights Reserved.
0018: *
0019: * Contributor(s):
0020: *
0021: * $Id: StandardSessionManager.java,v 1.4 2007-10-19 10:05:39 sinisa Exp $
0022: */
0023:
0024: package com.lutris.appserver.server.sessionEnhydra;
0025:
0026: import java.lang.reflect.Constructor;
0027: import java.util.Date;
0028: import java.util.Enumeration;
0029:
0030: import javax.servlet.http.HttpSession;
0031: import javax.servlet.http.HttpSessionBindingEvent;
0032: import javax.servlet.http.HttpSessionBindingListener;
0033:
0034: import com.lutris.appserver.server.Application;
0035: import com.lutris.appserver.server.Enhydra;
0036: import com.lutris.appserver.server.httpPresentation.HttpPresentationComms;
0037: import com.lutris.appserver.server.httpPresentation.HttpPresentationException;
0038: import com.lutris.appserver.server.session.MemoryPersistence;
0039: import com.lutris.appserver.server.session.Session;
0040: import com.lutris.appserver.server.session.SessionException;
0041: import com.lutris.appserver.server.session.SessionManager;
0042: import com.lutris.appserver.server.sessionEnhydra.persistent.PersistentSessionHome;
0043: import com.lutris.appserver.server.sessionEnhydra.persistent.PersistentSessionUserTable;
0044: import com.lutris.appserver.server.user.User;
0045: import com.lutris.logging.LogChannel;
0046: import com.lutris.logging.Logger;
0047: import com.lutris.util.Config;
0048: import com.lutris.util.ConfigException;
0049: import com.lutris.util.KeywordValueException;
0050:
0051: /**
0052: * This session manager maintains the mapping between session keys and sessions.
0053: * It generates secure session keys that are safe to use as cookie values in web
0054: * applications. It also manages the life of a session. If a session is not used
0055: * (touched) for a preconfigured amount of time, then it is expired and removed
0056: * from the session manager. The following parameters can be used to configure
0057: * the session manager. They should be grouped together in a section, normally
0058: * <code>SessionManager</code>, which is specified to the constructor.
0059: * <p>
0060: * <ul>
0061: * <li><code>SessionLifetimeMax: {int}</code>
0062: * <p>
0063: *
0064: * The maximum number of minutes a session is valid. If this value us zero, then
0065: * there is no lifetime limit. This parameter must be set in the configuration
0066: * file.
0067: * <p>
0068: *
0069: * <li><code>SessionIdleTimeMax: {int}</code>
0070: * <p>
0071: *
0072: * Maximum number of minutes a session may be idle before the session is expired
0073: * (deleted). If this value is less than or equal to zero, then the session may
0074: * be idle indefinitly.
0075: * <p>
0076: *
0077: * <li><code>SessionNoUserIdleTimeMax: {int}</code>
0078: * <p>
0079: *
0080: * Maximum number of minutes a session that does not have a <CODE>User</CODE>
0081: * object assocaited with it may be idle before the session is expired
0082: * (deleted). If this value is less than or equal to zero, then the session may
0083: * be idle indefinitly. Default is the same as <code>MaxIdleTime</code>
0084: * <p>
0085: *
0086: * <li><code>IdleScanInterval: {int}</code>
0087: * <p>
0088: *
0089: * How often, in seconds, the session manager tests if any sessions should be
0090: * expired. This parameter must be greater than zero.
0091: * <p>
0092: *
0093: * <li><code>RandomizerIntervals: {int [,int]...}</code>
0094: * <p>
0095: *
0096: * The set of varying intervals to use for adding user-generated entropy to the
0097: * random number generator. It is a good idea to use several different prime
0098: * numbers. These intervals are in seconds.
0099: * <p>
0100: *
0101: * <li><code>SessionHome.Mode: {BASIC | PAGE_TO_DISK | PAGE_TO_DB | CUSTOM}</code>
0102: * <p>
0103: *
0104: * Indicates the mode (StandardSessionHome interface) that the standard session
0105: * manager will use. In 'BASIC' mode the standard session manager uses the
0106: * <code>BasicSessionHome</code> to manage sessions. In 'PAGE_TO_DISK' the
0107: * standard session manager uses the <code>DiskPagedSessionHome</code> to
0108: * manage sessions. In 'PAGE_TO_DB' the standard session manager used the
0109: * <code>PersistentSessionHome</code> to manage sessions. In 'CUSTOM' the
0110: * application specifies the classes that should be loaded and provide the
0111: * <code>StandardSessionHome</code> implementation. If set to 'CUSTOM' then
0112: * the settings <code>SessionHome.Class</code> and
0113: * <code>SessionUserTable.Class</code> should be set.
0114: *
0115: * <li><code>SessionHome.Class: {String}</code>
0116: * <p>
0117: *
0118: * The class that implements the StandardSessionHome interface. This class is
0119: * loaded by StandardSessionManager and used to managed the collection of
0120: * sessions. If this option is not specified then BasicSessionHome is used. The
0121: * SessionHome that is loaded by the session manager is expected to contain a
0122: * consturctor that takes the following arguments:
0123: * <code>SessionHome(StandardSessionManager mgr,
0124: * com.lutris.util.Config config,
0125: * ClassLoader loader)</code>
0126: * <p>
0127: *
0128: * <li><code>SessionUserTable.Class: {String}</code>
0129: * <p>
0130: *
0131: * The class that implements the StandardSessiondUserTable interface. This class
0132: * is loaded by StandardSessionManager and used to managed the session to user
0133: * relationships. If this option is not specified then BasicSessionUserTable is
0134: * used. The SessionUserTable that is loaded by the session manager is expected
0135: * to contain a consturctor that takes the following arguments:
0136: * <code>SessionUserTable(com.lutris.util.Config config)</code>
0137: * <p>
0138: *
0139: * <li><code>MemoryPersistence: {true|false}</code>
0140: * <p>
0141: *
0142: * Indicate that should we keep sessions in memory when stop application
0143: *
0144: * </ul>
0145: *
0146: * @version $Revision: 1.4 $
0147: * @author John Marco
0148: * @author Shawn McMurdo
0149: * @author Kyle Clark
0150: * @author Mark Diekhans
0151: * @see com.lutris.util.Config
0152: * @see StandardSessionHome
0153: * @see StandardSessionUserTable
0154: * @see BasicSessionHome
0155: * @see DiskPagedSessionHome
0156: * @see com.lutris.appserver.server.sessionEnhydra.persistent.PersistentSessionHome
0157: */
0158: public class StandardSessionManager implements SessionManager,
0159: StandardSessionIdleHandler {
0160: /**
0161: * Represents the current session management mode.
0162: */
0163: protected int mode;
0164:
0165: /**
0166: * Indicates that the session manager is using the basic session home
0167: * interface to manage sessions.
0168: *
0169: * @see #getMode
0170: * @see com.lutris.appserver.server.sessionEnhydra.BasicSessionHome
0171: */
0172: public static final int MODE_BASIC = 1;
0173:
0174: /**
0175: * Indicates that the session manager is using the page to disk home
0176: * interface to manage sessions.
0177: *
0178: * @see #getMode
0179: * @see com.lutris.appserver.server.sessionEnhydra.DiskPagedSessionHome
0180: */
0181: public static final int MODE_PAGE_TO_DISK = 2;
0182:
0183: /**
0184: * Indicates that the session manager is using the page to database home
0185: * interface to manage sessions.
0186: *
0187: * @see #getMode
0188: * @see com.lutris.appserver.server.sessionEnhydra.persistent.PersistentSessionHome
0189: */
0190: public static final int MODE_PAGE_TO_DB = 3;
0191:
0192: /**
0193: * Indicates that the session manager is using the custom home interface to
0194: * manage sessions.
0195: *
0196: * @see #getMode
0197: */
0198: public static final int MODE_CUSTOM = 4;
0199:
0200: /**
0201: * Indicates that url encoding of session ids is never preformed.
0202: *
0203: * @see #getEncodeUrlState
0204: */
0205: public static final String ENCODE_URL_NEVER = "Never";
0206:
0207: /**
0208: * Indicates that url encoding of session ids is always preformed.
0209: *
0210: * @see #getEncodeUrlState
0211: */
0212: public static final String ENCODE_URL_ALWAYS = "Always";
0213:
0214: /**
0215: * Indicates that url encoding of session ids is preformed only when cookies
0216: * are disabled on the client browser. This is automatically detected.
0217: *
0218: * @see #getEncodeUrlState
0219: */
0220: public static final String ENCODE_URL_AUTO = "Auto";
0221:
0222: public static final String ENCODE_RANDOM_YES = "Yes";
0223:
0224: public static final String ENCODE_RANDOM_NO = "No";
0225:
0226: /**
0227: * Default maximum session life time, in seconds. Zero if there is no limit.
0228: * A derived <CODE>SessionManager</CODE> may override this value to use
0229: * the default expiration logic or override <CODE>isSessionExpired</CODE>
0230: * to define custom expiration logic.
0231: *
0232: * @see lutris.session.StandardSessionManager#getMaxSessionLifeTime
0233: */
0234: protected static long defaultMaxSessionLifeTime = 0;
0235:
0236: /**
0237: * Default maximum session idle time, in seconds. A derived <CODE>SessionManager</CODE>
0238: * may override this value to use the default expiration logic or override
0239: * <CODE>isSessionExpired</CODE> to define custom expiration logic. A
0240: * value less-than or equal to zero disables idle checking. Default value is
0241: * 30 minutes.
0242: *
0243: * @see #getMaxSessionIdleTime
0244: */
0245: protected static long defaultMaxSessionIdleTime = 30 * 60;
0246:
0247: /**
0248: * Indicates url encoding status. Assumes that
0249: * comms.response.writeHTML(HTMLDocument doc) is used to commit the response
0250: * to the client. The default is to Auto.<br>
0251: * <code>Never</code> indicates urls are never encoded with session keys.
0252: * This indicates that session cookies have to be used or no session state
0253: * can be maintained.<br>
0254: * <code>Always</code> indicates that urls are always encoded with session
0255: * keys. Session cookies are never used.<br>
0256: * <code>Auto</code> indicates that session cookies will be if available.
0257: * If not, urls will automatically be encoded.<br>
0258: *
0259: * @see #getEncodeUrlState
0260: */
0261: protected static String defaultEncodeUrlState = "Auto";
0262:
0263: /**
0264: * Default interval, in seconds, to scan for sessions to expire. A derived
0265: * <CODE>SessionManager</CODE> may override this value. Default value is
0266: * 30 seconds.
0267: */
0268: protected static long defaultIdleScanInterval = 30;
0269:
0270: /**
0271: * Default list of randomize key generator time intervals, in seconds. A
0272: * list of prime numbers is recommended. A derived <CODE>SessionManager</CODE>
0273: * may override this value.
0274: */
0275: protected static long[] defaultRandomizerIntervals = { 301, 1001,
0276: 5003 };
0277:
0278: /**
0279: * Determins whether to use empty path (/) as session cookie path attribute
0280: * value! Default value is false which means - use application context path.
0281: */
0282: protected static boolean defaultEmptySessionPath = false;
0283:
0284: /**
0285: * The name of the config variable for the EmptySessionPath.
0286: */
0287: public static final String CFG_EMPTY_SESSION_PATH = "EmptySessionPath";
0288:
0289: /**
0290: * The name of the config variable for the max session lifetime.
0291: */
0292: public static final String CFG_LIFE = "SessionLifetimeMax";
0293:
0294: /**
0295: * The name of the config variable for the max session idle time.
0296: */
0297: public static final String CFG_IDLE = "SessionIdleTimeMax";
0298:
0299: /**
0300: * The name of the config variable for the url encoding state
0301: */
0302: public static final String CFG_ENCODE_URL_STATE = "SessionEncodeUrlState";
0303:
0304: /**
0305: * Url encoding for first page state (to force it or not)
0306: * CFG_ENCODE_URL_STATE must not be set to NEVER for this parameter to take
0307: * efect
0308: */
0309: public static final String CFG_ENCODE_FIRST_URL = "SessionEncodeFirstUrl";
0310:
0311: /**
0312: * The name of the config variable for the max idle time for sessions with
0313: * no user.
0314: */
0315: public static final String CFG_NOUSER_IDLE = "SessionNoUserIdleTimeMax";
0316:
0317: /**
0318: * The name of the config variable for the interval between scans for idle
0319: * sessions.
0320: */
0321: public static final String CFG_SCAN = "IdleScanInterval";
0322:
0323: /**
0324: * The name of the config variable for the interval between introduction of
0325: * randomness to the session key generator.
0326: */
0327: public static final String CFG_RANDOM = "RandomizerIntervals";
0328:
0329: /**
0330: * The name of the config variable for the session home settings.
0331: */
0332: public static final String CFG_SESSION_HOME = "SessionHome";
0333:
0334: /**
0335: * The name of the config variable for the session home type.
0336: */
0337: public static final String CFG_SESSION_HOME_TYPE = "SessionHome.Mode";
0338:
0339: /**
0340: * Indicates that a sesson is still active.
0341: *
0342: * @see #sessionDeleted
0343: */
0344: public static final int SESSION_ACTIVE = 0;
0345:
0346: /**
0347: * Indicates that a sesson was deleted due to max time being exceeded.
0348: *
0349: * @see #sessionDeleted
0350: */
0351: public static final int SESSION_MAX_TIME = 1;
0352:
0353: /**
0354: * Indicates that a sesson was deleted due to idle time being exceeded.
0355: *
0356: * @see #sessionDeleted
0357: */
0358: public static final int SESSION_IDLE_EXPIRE = 2;
0359:
0360: /**
0361: * Indicates that a sesson was explictly deleted.
0362: *
0363: * @see #sessionDeleted
0364: */
0365: public static final int SESSION_EXPLICT_DELETE = 3;
0366:
0367: /**
0368: * Table of currently active user sessions is managed by the session home.
0369: * Different implementations of StandardSessionHome can be loaded by this
0370: * manager. A specific implementation can manage failover persistence,
0371: * paging, etc.
0372: */
0373: // private StandardSessionHome sessionHome;
0374: protected StandardSessionHome sessionHome;
0375:
0376: /**
0377: * Table of users objects. This table tracks the number of simultaneous
0378: * sessions a user currently has active. Table entries are of type <CODE>Vector</CODE>,
0379: * constaining Session objects, keyed by User object reference.
0380: */
0381: private StandardSessionUserTable sessionUserTable;
0382:
0383: // The maximum number of sessions (highwater mark).
0384: protected int maxSessions;
0385:
0386: protected Date maxSessionsDate;
0387:
0388: /**
0389: * Object that generates random session keys. Manages a thread to for
0390: * increase randomization.
0391: *
0392: * @see StandardSessionKeyGen
0393: */
0394: private StandardSessionKeyGen keyGenerator;
0395:
0396: /**
0397: * Maximum session life time, in seconds. Zero if there is no limit.
0398: *
0399: * @see lutris.session.StandardSessionManager#getMaxSessionLifeTime
0400: */
0401: private long maxSessionLifeTime;
0402:
0403: /**
0404: * Maximum session idle time, in seconds. A value less-than or equal to zero
0405: * disables idle checking.
0406: *
0407: * @see #getMaxSessionIdleTime
0408: */
0409: protected long maxSessionIdleTime;
0410:
0411: /**
0412: * The url encoding state. Either <code>Never</code>
0413: * <code>Always</code> <code>Auto</code>.
0414: */
0415: protected String encodeUrlState;
0416:
0417: /**
0418: * Url encoding for first page state (force it or not)
0419: */
0420: protected boolean encodeFirstUrl;
0421:
0422: /**
0423: * Background thread that keeps track of session idle time. Sessions that
0424: * have been idle for more than a configurable time limit are terminated by
0425: * this thread.
0426: *
0427: * @see StandardSessionIdleTimer
0428: */
0429: private StandardSessionIdleTimer idleTimer;
0430:
0431: /**
0432: * Maximum session idle time, in seconds for sessions that don't have a
0433: * <CODE>User</CODE> object associated with them. A value less-than or
0434: * equal to zero disables idle checking.
0435: *
0436: * @see #getMaxNoUserSessionIdleTime
0437: */
0438: protected long maxNoUserSessionIdleTime;
0439:
0440: /**
0441: * The time in seconds between scans for idle sessions to expire.
0442: */
0443: protected long scanInterval;
0444:
0445: /**
0446: * determins whether to use empty path (/) as session cookie path attribute
0447: * value!
0448: */
0449: protected boolean emptySessionPath;
0450:
0451: /**
0452: * Log channel for debugging messages.
0453: */
0454: LogChannel logChannel = null;
0455:
0456: /**
0457: * The application using this session manager.
0458: */
0459: Application app = null;
0460:
0461: /**
0462: * The class loader used by this app/context.
0463: */
0464: ClassLoader classLoader;
0465:
0466: /**
0467: * The supported session home types.
0468: */
0469: private static final String BASIC = "BASIC";
0470:
0471: private static final String PAGE_TO_DISK = "PAGE_TO_DISK";
0472:
0473: private static final String PAGE_TO_DB = "PAGE_TO_DB";
0474:
0475: private static final String CUSTOM = "CUSTOM";
0476:
0477: /**
0478: * The session home interface type being used.
0479: */
0480: String sessionHomeType = BASIC;
0481:
0482: /**
0483: * DACHA & TUFA variable which determine should we held sessions in memory
0484: * during restart application
0485: */
0486: private boolean isMemoryPersistence = false;
0487:
0488: /**
0489: * Log configuration information.
0490: */
0491: private void logConfig() {
0492: if (logChannel != null) {
0493: logChannel.write(Logger.DEBUG, "SessionManager." + CFG_LIFE
0494: + " = " + maxSessionLifeTime + " sec");
0495: logChannel.write(Logger.DEBUG, "SessionManager." + CFG_IDLE
0496: + " = " + maxSessionIdleTime + " sec");
0497: logChannel.write(Logger.DEBUG, "SessionManager."
0498: + CFG_NOUSER_IDLE + " = "
0499: + maxNoUserSessionIdleTime + " sec");
0500: logChannel.write(Logger.DEBUG, "SessionManager." + CFG_SCAN
0501: + " = " + scanInterval + " sec");
0502: logChannel.write(Logger.DEBUG, "SessionManager."
0503: + CFG_ENCODE_URL_STATE + " = " + encodeUrlState);
0504: logChannel.write(Logger.DEBUG, "SessionManager."
0505: + CFG_ENCODE_FIRST_URL + " = " + encodeFirstUrl);
0506: logChannel
0507: .write(Logger.DEBUG, "SessionManager."
0508: + CFG_EMPTY_SESSION_PATH + " = "
0509: + emptySessionPath);
0510: }
0511: }
0512:
0513: public StandardSessionManager() {
0514: }
0515:
0516: /**
0517: * Creates a new <code>SessionManager</code> object. This constructor will
0518: * first looks for the session manager configuration parameters that have
0519: * the specified configuration prefix prepended to the standard session
0520: * manager configuration option.
0521: * <p>
0522: *
0523: * @param app
0524: * the application associate with this session manager.
0525: * @param config
0526: * Object parsed from configuration file. This should be for the
0527: * section constaining the session manager configuration.
0528: * @param sessionMgrLogChannel
0529: * If not <CODE>null</CODE>, channel to log debugging
0530: * information to.
0531: * @exception ConfigException
0532: * signifies a problem in the configuration file.
0533: * @exception SessionException
0534: * if all classes (Home and UserTable) couldn't be loaded by
0535: * the session manager.
0536: */
0537: public StandardSessionManager(Application application,
0538: Config config, LogChannel sessionMgrLogChannel)
0539: throws ConfigException, SessionException {
0540: // DACHA: first initialize app
0541: app = application;
0542: initManager(application.getClass().getClassLoader(), config,
0543: sessionMgrLogChannel);
0544: }
0545:
0546: public StandardSessionManager(ClassLoader classLoader,
0547: Config config, LogChannel sessionMgrLogChannel)
0548: throws ConfigException, SessionException {
0549: initManager(classLoader, config, sessionMgrLogChannel);
0550: }
0551:
0552: private void initManager(ClassLoader classLoader, Config config,
0553: LogChannel sessionMgrLogChannel) throws ConfigException,
0554: SessionException {
0555: this .classLoader = classLoader;
0556: logChannel = sessionMgrLogChannel;
0557: // High-water mark
0558: maxSessions = 0;
0559: maxSessionsDate = new Date();
0560: /**
0561: * DACHA & TUFA Config file specifies should we keep SessionManager in
0562: * memory during restart application
0563: */
0564: if (config.containsKey("MemoryPersistence")) {
0565: String mp = config.getString("MemoryPersistence");
0566: if (mp.equals("true"))
0567: isMemoryPersistence = true;
0568: }
0569: /*
0570: * Config file specifies minutes, but the values are kept internally as
0571: * seconds.
0572: */
0573: // Session lifetime
0574: if (config.containsKey(CFG_LIFE)) {
0575: maxSessionLifeTime = config.getLong(CFG_LIFE) * 60;
0576: } else if (config.containsKey("Lifetime")) {
0577: // backwards compatability
0578: maxSessionLifeTime = config.getLong("Lifetime") * 60;
0579: } else {
0580: maxSessionLifeTime = defaultMaxSessionLifeTime;
0581: }
0582: // Idle time.
0583: if (config.containsKey(CFG_IDLE)) {
0584: maxSessionIdleTime = config.getLong(CFG_IDLE) * 60;
0585: } else if (config.containsKey("MaxIdleTime")) {
0586: // backwards compatability
0587: maxSessionIdleTime = config.getLong("MaxIdleTime") * 60;
0588: } else {
0589: maxSessionIdleTime = defaultMaxSessionIdleTime;
0590: }
0591: // Url encoding state
0592: if (config.containsKey(CFG_ENCODE_URL_STATE)) {
0593: encodeUrlState = config.getString(CFG_ENCODE_URL_STATE);
0594: } else if (config.containsKey("EncodeUrlState")) {
0595: // backwards compatability
0596: encodeUrlState = config.getString("EncodeUrlState");
0597: } else {
0598: encodeUrlState = defaultEncodeUrlState;
0599: }
0600: if (!encodeUrlState.equalsIgnoreCase(ENCODE_URL_NEVER)
0601: && !encodeUrlState.equalsIgnoreCase(ENCODE_URL_ALWAYS)
0602: && !encodeUrlState.equalsIgnoreCase(ENCODE_URL_AUTO)) {
0603: throw new ConfigException(
0604: "EncodeUrlState must be one of the following: "
0605: + ENCODE_URL_NEVER + ", "
0606: + ENCODE_URL_ALWAYS + ", or "
0607: + ENCODE_URL_AUTO + ".");
0608: }
0609:
0610: /**
0611: * Url encoding for first page state (to force it or not)
0612: * CFG_ENCODE_URL_STATE must not be set to NEVER for this parameter to
0613: * take efect
0614: */
0615: if (config.containsKey(CFG_ENCODE_FIRST_URL)) {
0616: encodeFirstUrl = config.getBoolean(CFG_ENCODE_FIRST_URL,
0617: false);
0618: } else {
0619: encodeFirstUrl = false;
0620: }
0621:
0622: /**
0623: * Whether to use empty path for session cookies
0624: */
0625: if (config.containsKey(CFG_EMPTY_SESSION_PATH)) {
0626: emptySessionPath = config.getBoolean(
0627: CFG_EMPTY_SESSION_PATH, false);
0628: } else {
0629: emptySessionPath = false;
0630: }
0631:
0632: /**
0633: * if CFG_ENCODE_URL_STATE is set to ALWAYS or NEVER ignore original and
0634: * set adequate CFG_ENCODE_FIRST_URL parameter value
0635: */
0636: if (encodeUrlState.equalsIgnoreCase(ENCODE_URL_ALWAYS)) {
0637: encodeFirstUrl = true;
0638: } else if (encodeUrlState.equalsIgnoreCase(ENCODE_URL_NEVER)) {
0639: encodeFirstUrl = false;
0640: }
0641:
0642: if (config.containsKey(CFG_NOUSER_IDLE)) {
0643: maxNoUserSessionIdleTime = config.getLong(CFG_NOUSER_IDLE) * 60;
0644: } else if (config.containsKey("MaxNoUserIdleTime")) {
0645: // backwards compatability
0646: maxNoUserSessionIdleTime = config
0647: .getLong("MaxNoUserIdleTime") * 60;
0648: } else {
0649: maxNoUserSessionIdleTime = maxSessionIdleTime;
0650: }
0651: scanInterval = defaultIdleScanInterval;
0652: if (config.containsKey(CFG_SCAN)) {
0653: scanInterval = config.getLong(CFG_SCAN);
0654: } else if (config.containsKey("IdleScanInterval")) {
0655: // backwards compatability
0656: scanInterval = config.getLong("IdleScanInterval");
0657: }
0658: if (scanInterval <= 0) {
0659: throw new ConfigException(
0660: "IdleScanInterval must be greater than zero.");
0661: }
0662: idleTimer = new StandardSessionIdleTimer(this , app,
0663: scanInterval);
0664: if (config.containsKey(CFG_SESSION_HOME_TYPE)) {
0665: sessionHomeType = config.getString(CFG_SESSION_HOME_TYPE);
0666: }
0667: if (!sessionHomeType.equalsIgnoreCase(BASIC)
0668: && !sessionHomeType.equalsIgnoreCase(PAGE_TO_DISK)
0669: && !sessionHomeType.equalsIgnoreCase(PAGE_TO_DB)
0670: && !sessionHomeType.equalsIgnoreCase(CUSTOM)) {
0671: throw new ConfigException("Invalid "
0672: + CFG_SESSION_HOME_TYPE + ": '" + sessionHomeType
0673: + "'");
0674: }
0675: // Session Home
0676: sessionHome = loadSessionHome(config);
0677: // Session User Table
0678: sessionUserTable = loadSessionUserTable(config);
0679: // Random key generator.
0680: long[] intervals = config.getLongs(CFG_RANDOM,
0681: defaultRandomizerIntervals);
0682: if (intervals.length == 0) {
0683: throw new ConfigException(CFG_RANDOM
0684: + " must contain some values.");
0685: }
0686: for (int i = 0; i < intervals.length; i++) {
0687: if (intervals[i] <= 0) {
0688: throw new ConfigException(CFG_RANDOM
0689: + " must contain positive integers.");
0690: }
0691: }
0692: keyGenerator = new StandardSessionKeyGen(intervals);
0693: // Start threads.
0694: keyGenerator.start();
0695: idleTimer.start();
0696: logConfig();
0697: }
0698:
0699: /**
0700: * Loads the StandardSessionHome used by this session manager.
0701: *
0702: * @param config
0703: * This session manager's config section.
0704: * @exception ConfigException
0705: * if the configuration is invalid.
0706: * @exception SessionException
0707: * if the StandardSessionHome could not be loaded.
0708: */
0709: protected StandardSessionHome loadSessionHome(Config config)
0710: throws ConfigException, SessionException {
0711: try {
0712: StandardSessionHome sessionHome = null;
0713: Config homeConfig = null;
0714: if (config.containsKey(CFG_SESSION_HOME)) {
0715: homeConfig = (Config) config
0716: .getSection(CFG_SESSION_HOME);
0717: } else {
0718: homeConfig = new Config();
0719: }
0720: if (sessionHomeType.equalsIgnoreCase(CUSTOM)) {
0721: if (homeConfig.containsKey("Class")) {
0722: String homeClassName = homeConfig
0723: .getString("Class");
0724: try {
0725: Class[] paramTypes = new Class[3];
0726: Object[] args = new Object[3];
0727: paramTypes[0] = Class
0728: .forName("com.lutris.appserver.server.sessionEnhydra.StandardSessionManager");
0729: paramTypes[1] = Class
0730: .forName("com.lutris.util.Config");
0731: paramTypes[2] = Class
0732: .forName("java.lang.ClassLoader");
0733: args[0] = this ;
0734: args[1] = homeConfig;
0735: args[2] = classLoader;
0736: Constructor c = Class.forName(homeClassName)
0737: .getConstructor(paramTypes);
0738: sessionHome = (StandardSessionHome) c
0739: .newInstance(args);
0740: if (logChannel != null) {
0741: logChannel.write(Logger.DEBUG,
0742: "SessionMgr: "
0743: + "StandardSessionHome: "
0744: + homeClassName);
0745: }
0746: } catch (Exception e) {
0747: throw new SessionException("Unable to load "
0748: + homeClassName, e);
0749: }
0750: }
0751: mode = MODE_CUSTOM;
0752: } else if (sessionHomeType.equalsIgnoreCase(PAGE_TO_DISK)) {
0753: sessionHome = new DiskPagedSessionHome(this ,
0754: homeConfig, classLoader);
0755: mode = MODE_PAGE_TO_DISK;
0756: } else if (sessionHomeType.equalsIgnoreCase(PAGE_TO_DB)) {
0757: sessionHome = new PersistentSessionHome(this ,
0758: homeConfig, classLoader);
0759: mode = MODE_PAGE_TO_DB;
0760: } else {
0761: sessionHome = new BasicSessionHome(this , homeConfig);
0762: mode = MODE_BASIC;
0763: }
0764: if (logChannel != null) {
0765: logChannel.write(Logger.DEBUG, "SessionMgr: "
0766: + "StandardSessionHome: " + sessionHomeType
0767: + "\n");
0768: }
0769: return sessionHome;
0770: } catch (KeywordValueException e) {
0771: e.printStackTrace();
0772: throw new ConfigException(
0773: "SessionMgr: unable to load StandardSessionHome: "
0774: + e);
0775: }
0776: }
0777:
0778: /**
0779: * Loads the StandardSessiondUserTable used by this session manager.
0780: *
0781: * @param config
0782: * This session manager's config section.
0783: * @exception ConfigException
0784: * if the StandardSessionHome could not be loaded.
0785: */
0786: protected StandardSessionUserTable loadSessionUserTable(
0787: Config config) throws ConfigException, SessionException {
0788: try {
0789: StandardSessionUserTable sessionUserTable = null;
0790: Config userTableConfig = null;
0791: if (config.containsKey("SessionUserTable")) {
0792: userTableConfig = (Config) config
0793: .getSection("SessionUserTable");
0794: } else {
0795: userTableConfig = new Config();
0796: }
0797: if (sessionHomeType.equalsIgnoreCase(CUSTOM)) {
0798: String tableClassName = userTableConfig
0799: .getString("Class");
0800: try {
0801: Class[] paramTypes = new Class[1];
0802: Object[] args = new Object[1];
0803: paramTypes[0] = Class
0804: .forName("com.lutris.util.Config");
0805: args[0] = userTableConfig;
0806: Constructor c = Class.forName(tableClassName)
0807: .getConstructor(paramTypes);
0808: sessionUserTable = (StandardSessionUserTable) c
0809: .newInstance(args);
0810: if (logChannel != null) {
0811: logChannel.write(Logger.DEBUG, "SessionMgr: "
0812: + "StandardSessionUserTable: "
0813: + tableClassName);
0814: }
0815: } catch (NoSuchMethodException e) {
0816: throw new SessionException("Unable to load "
0817: + tableClassName + ": "
0818: + "Constructor not found.", e);
0819: } catch (Exception e) {
0820: throw new SessionException(
0821: "Unable to create instance of "
0822: + tableClassName, e);
0823: }
0824: } else if (sessionHomeType.equalsIgnoreCase(PAGE_TO_DISK)) {
0825: sessionUserTable = new PagedSessionUserTable(
0826: userTableConfig);
0827: } else if (sessionHomeType.equalsIgnoreCase(PAGE_TO_DB)) {
0828: sessionUserTable = new PersistentSessionUserTable(
0829: userTableConfig);
0830: } else {
0831: sessionUserTable = new BasicSessionUserTable(
0832: userTableConfig);
0833: }
0834: return sessionUserTable;
0835: } catch (KeywordValueException e) {
0836: throw new ConfigException(
0837: "SessionMgr: unable to load StandardSessionUserTable: "
0838: + e);
0839: }
0840: }
0841:
0842: /**
0843: * Shutdown this session manager, stopping threads that are associated with
0844: * it.
0845: */
0846: public synchronized void shutdown() {
0847: if (isMemoryPersistence)
0848: MemoryPersistence.putSessionManager(app.getName(), this );
0849: else {
0850: if (keyGenerator != null) {
0851: keyGenerator.shutdown();
0852: keyGenerator = null;
0853: }
0854: if (idleTimer != null) {
0855: idleTimer.shutdown();
0856: idleTimer = null;
0857: }
0858: if (sessionHome != null) {
0859: sessionHome.shutdown();
0860: sessionHome = null;
0861: }
0862: if (sessionUserTable != null) {
0863: sessionUserTable.shutdown();
0864: sessionUserTable = null;
0865: }
0866: }
0867: }
0868:
0869: /**
0870: * Allocate a new <CODE>StandardSession</CODE> object. This maybe
0871: * overridden by derived session managers to allocated a <CODE>Session</CODE>
0872: * object derived from <CODE>StandardSession</CODE>. This is called by
0873: * <CODE>createSession</CODE>.
0874: *
0875: * @param sessionKey
0876: * The session key to associate with the session.
0877: * @return session The new <code>StandardSession</code> object.
0878: * @see StandardSession
0879: * @deprecated The instance of StandardSessionHome should be replaced
0880: * instead of extending this method.
0881: */
0882: protected StandardSession newSession(String sessionKey)
0883: throws CreateSessionException, SessionException {
0884: return (StandardSession) sessionHome.createSession(sessionKey);
0885: }
0886:
0887: /**
0888: * Create a new <CODE>Session</CODE> object and associate a unique random
0889: * key. No <CODE>User</CODE> is initially associated with (<CODE>Session.getUser()</CODE>
0890: * returns <CODE>null</CODE>/
0891: *
0892: * @return session The new <code>Session</code> object.
0893: * @exception SessionException
0894: * if the session cannot be created.
0895: * @see Session
0896: */
0897: public Session createSession() throws SessionException {
0898: return createSession("");
0899: }
0900:
0901: /**
0902: * Create a new <CODE>Session</CODE> object and associate a unique random
0903: * key. No <CODE>User</CODE> is initially associated with (<CODE>Session.getUser()</CODE>
0904: * returns <CODE>null</CODE>/
0905: *
0906: * @param ipPortToken
0907: * The base64 encoded IP and Port number to include in session
0908: * key
0909: * @return session The new <code>Session</code> object.
0910: * @exception SessionException
0911: * if the session cannot be created.
0912: * @see Session
0913: */
0914: public Session createSession(String ipPortToken)
0915: throws SessionException {
0916: StandardSession session = null;
0917: String sessionKey = null;
0918: /*
0919: * Create a new key that does not already exist in the session table.
0920: * The odds of this loop making more than one pass are astronomically
0921: * small, but not zero.
0922: */
0923: do {
0924: try {
0925: sessionKey = keyGenerator.newSessionKey();
0926: if (ipPortToken != null && ipPortToken.length() > 0) {
0927: sessionKey = sessionKey.substring(0, sessionKey
0928: .length() - 2)
0929: + ipPortToken;
0930: }
0931: session = sessionHome.createSession(sessionKey);
0932: } catch (DuplicateKeyException e) {
0933: // TODO - log message?
0934: session = null;
0935: }
0936: } while (session == null);
0937: int currentSize = sessionHome.size();
0938: if (currentSize > maxSessions) {
0939: maxSessions = currentSize;
0940: maxSessionsDate = new Date();
0941: }
0942: keyGenerator.incrementRandomCounter();
0943: if (logChannel != null) {
0944: logChannel.write(Logger.DEBUG,
0945: "SessionMgr: createSession: " + sessionKey);
0946: }
0947: return session;
0948: }
0949:
0950: public Session createSession(HttpPresentationComms comms)
0951: throws SessionException {
0952: Session s = null;
0953: String saTok = null;
0954: try {
0955: saTok = comms.request.getHeader(":aff:");
0956: } catch (HttpPresentationException hpe) {
0957: saTok = null;
0958: }
0959: if (saTok == null) {
0960: s = createSession();
0961: } else {
0962: s = createSession(saTok);
0963: if (logChannel != null) {
0964: logChannel.write(Logger.DEBUG,
0965: "SessionKey created for EnhydraDirector");
0966: }
0967: }
0968: return s;
0969: }
0970:
0971: /**
0972: * Log a user being registered or unregistered.
0973: */
0974: private void logRegisterUser(Session session, String which) {
0975: if (logChannel != null) {
0976: String userName = null;
0977: User user = session.getUser();
0978: if (user != null) {
0979: userName = user.getName();
0980: }
0981: logChannel.write(Logger.DEBUG, "SessionMgr: " + which
0982: + ": " + session.getSessionKey() + " user = \""
0983: + userName + "\"");
0984: }
0985: }
0986:
0987: /**
0988: * Adds a session's user to the session-to-user table. This is called by the
0989: * <CODE>Session</CODE> object to associate a session with a user.
0990: *
0991: * @param session
0992: * The now logged-in <code>Session</code> instance to store in
0993: * the session table.
0994: * @see Session
0995: * @see User
0996: * @see #unregisterUser
0997: * @exception SessionException
0998: * if an error occurs.
0999: */
1000: protected synchronized void registerUser(Session session)
1001: throws SessionException {
1002: sessionUserTable
1003: .add(session.getSessionKey(), session.getUser());
1004: logRegisterUser(session, "registerUser");
1005: }
1006:
1007: /**
1008: * Removes a session's user from the session-to-user table. This is called
1009: * by the <CODE>Session</CODE> object to disassoicate a user from a
1010: * session.
1011: *
1012: * @param session
1013: * The now <code>Session</code> instance the user is being
1014: * logged out from.
1015: * @see Session
1016: * @exception SessionException
1017: * if an error occurs.
1018: */
1019: protected synchronized void unregisterUser(Session session)
1020: throws SessionException {
1021: logRegisterUser(session, "unregisterUser");
1022: sessionUserTable.remove(session.getSessionKey(), session
1023: .getUser());
1024: }
1025:
1026: /**
1027: * Determine if a session should be expired based on the idle time. This
1028: * method is designed to be overriden by derived classes that want to use
1029: * different idle time checks.
1030: *
1031: * @param session
1032: * Session to check.
1033: * @return A reason code for the experation. One of <CODE>SESSION_MAX_TIME</CODE>,
1034: * <CODE>SESSION_IDLE_EXPIRE</CODE>, or <CODE>SESSION_ACTIVE</CODE>,
1035: * to indicate that the session is not expired.
1036: *
1037: * @see #sessionDeleted
1038: * @see #maxSessionIdleTime
1039: * @see #maxNoUserSessionIdleTime
1040: */
1041: protected int isSessionExpired(StandardSession session) {
1042: long now = System.currentTimeMillis();
1043: /*
1044: * Has the session reached it's maximum age, regardless of user
1045: * interaction? This is an optional feature.
1046: */
1047: long maxAge = session.getTimeExpires();
1048: if ((maxAge > 0) && (now > maxAge)) {
1049: return SESSION_MAX_TIME;
1050: }
1051: /*
1052: * Has the session been idle too long? There are two thresholds, for
1053: * whether or not a user is logged in. Both are optional features.
1054: */
1055: long idle = now - session.getTimeLastUsed();
1056: long maxIdle;
1057: if (session.getUser() != null) {
1058: maxIdle = session.getMaxIdleTime();
1059: } else {
1060: maxIdle = session.getMaxNoUserIdleTime();
1061: }
1062: if ((maxIdle > 0) && (idle > maxIdle)) {
1063: return SESSION_IDLE_EXPIRE;
1064: }
1065: /*
1066: * The session is ok.
1067: */
1068: return SESSION_ACTIVE;
1069: }
1070:
1071: /**
1072: * Method called when a session is deleted. This method is designed to be
1073: * overriden by derived classes that want need to take specific action, such
1074: * as saving the sessions state. The default implementation of this method
1075: * does nothing.
1076: *
1077: * @param session
1078: * Session that is being delete.
1079: * @param reason
1080: * The reason the session was being deleted. One of <CODE>SESSION_MAX_TIME</CODE>,
1081: * <CODE>SESSION_IDLE_EXPIRE</CODE>, <CODE>SESSION_EXPLICT_DELETE</CODE>.
1082: * @see #isSessionExpired
1083: */
1084: protected void sessionDeleted(Session session, int reason) {
1085: // Default implementation does nothing.
1086: }
1087:
1088: /**
1089: * Does the actual work of deleting an entry from the session table.
1090: *
1091: * @param session
1092: * The session to delete.
1093: * @param reason
1094: * The reason the session was being deleted.
1095: * @exception SessionException
1096: * If the session cannot be deleted.
1097: */
1098: private void doDeleteSession(StandardSession session, int reason)
1099: throws SessionException {
1100: keyGenerator.incrementRandomCounter();
1101: if (logChannel != null) {
1102: String userName = null;
1103: User user = session.getUser();
1104: if (user != null) {
1105: userName = user.getName();
1106: }
1107: String reasonMsg;
1108: switch (reason) {
1109: case SESSION_ACTIVE:
1110: reasonMsg = "SESSION_ACTIVE";
1111: break;
1112: case SESSION_MAX_TIME:
1113: reasonMsg = "SESSION_MAX_TIME";
1114: break;
1115: case SESSION_IDLE_EXPIRE:
1116: reasonMsg = "SESSION_IDLE_EXPIRE";
1117: break;
1118: case SESSION_EXPLICT_DELETE:
1119: reasonMsg = "SESSION_EXPLICT_DELETE";
1120: break;
1121: default:
1122: reasonMsg = "bad reason code " + reason;
1123: break;
1124: }
1125: logChannel.write(Logger.DEBUG, "SessionMgr deleteSession: "
1126: + session.getSessionKey() + " user = \"" + userName
1127: + "\" reason = " + reasonMsg);
1128: }
1129: // add by K.Nakamura
1130: // Call valueUnbound on session attributes
1131: HttpSession hs = session.getHttpSession();
1132: for (Enumeration e = hs.getAttributeNames(); e
1133: .hasMoreElements();) {
1134: String key = (String) e.nextElement();
1135: Object value = hs.getAttribute(key);
1136: if (value instanceof HttpSessionBindingListener) {
1137: try {
1138: ((HttpSessionBindingListener) value)
1139: .valueUnbound(new HttpSessionBindingEvent(
1140: hs, key));
1141: } catch (Exception ex) {
1142: // ignored
1143: }
1144: }
1145: }
1146: if (session.getUser() != null) {
1147: sessionUserTable.remove(session.getSessionKey(), session
1148: .getUser());
1149: }
1150: sessionHome.removeSession(session.getSessionKey());
1151: }
1152:
1153: /**
1154: * Removes a session from the Session Table. This method is used to log a
1155: * user off the application. Note that <CODE>sessionDeleted()</CODE> is
1156: * called.
1157: *
1158: * @param session
1159: * Session object to remove from table removed.
1160: * @exception SessionException
1161: * If the session cannot be deleted.
1162: */
1163: public synchronized void deleteSession(Session session)
1164: throws SessionException {
1165: sessionDeleted((StandardSession) session,
1166: SESSION_EXPLICT_DELETE);
1167: doDeleteSession((StandardSession) session,
1168: SESSION_EXPLICT_DELETE);
1169: }
1170:
1171: /**
1172: * Removes a session from the Session Table. This method is used to log a
1173: * user off the application. Note that <CODE>sessionDeleted()</CODE> is
1174: * called.
1175: *
1176: * @param sessionKey
1177: * A key corresponding to a user session to be removed.
1178: * @exception SessionException
1179: * If the session cannot be deleted.
1180: */
1181: public synchronized void deleteSession(String sessionKey)
1182: throws SessionException {
1183: Session session = (Session) sessionHome.getSession(Thread
1184: .currentThread(), sessionKey);
1185: if (session != null) {
1186: deleteSession(session);
1187: }
1188: }
1189:
1190: /**
1191: * Puts a session into the 'passive' state. A 'passive' session may be made
1192: * persistent.
1193: *
1194: * @param thread
1195: * the thread currently associated with the session.
1196: * @param sessionKey
1197: * the session key for the session that will be made persistent.
1198: * @exception SessionException
1199: * If the session cannot be put into the passive state.
1200: */
1201: public void passivateSession(Thread thread, String sessionKey)
1202: throws SessionException {
1203: sessionHome.passivateSession(thread, sessionKey);
1204: }
1205:
1206: /**
1207: * Scans session table to determine if any sessions need to be expired.
1208: *
1209: * @exception SessionException
1210: * if an error occurs.
1211: */
1212: public void cleanUpIdleSessions() throws SessionException {
1213: Enumeration e = sessionHome.keys();
1214: StandardSession session;
1215: String sessionKey;
1216: debug(3, "checking for idle sessions... ");
1217: while (e.hasMoreElements()) {
1218: sessionKey = (String) e.nextElement();
1219: session = (StandardSession) sessionHome.getSession(Thread
1220: .currentThread(), sessionKey);
1221: if (session != null) {
1222: int stat = isSessionExpired(session);
1223: if (stat != SESSION_ACTIVE) {
1224: debug(3, "cleaning up idle session: " + sessionKey);
1225: sessionDeleted(session, stat);
1226: doDeleteSession(session, stat);
1227: } else {
1228: sessionHome.passivateSession(
1229: Thread.currentThread(), sessionKey);
1230: }
1231: }
1232: }
1233: }
1234:
1235: /**
1236: * Returns whether the <code>Session</code> object associated with the
1237: * specified session key exists.
1238: *
1239: * @param sessionKey
1240: * The String used to reference a <code>Session</code> object.
1241: * @return If the key is associated with an active session, then return
1242: * true, otherwise return false.
1243: * @exception SessionException
1244: * If existence of the session cannot be tested.
1245: */
1246: public synchronized boolean sessionExists(String sessionKey)
1247: throws SessionException {
1248: if (sessionKey == null) {
1249: return false;
1250: }
1251: return sessionHome.containsKey(sessionKey);
1252: }
1253:
1254: /**
1255: * Lookup the <code>Session</code> object associated with the specified
1256: * session key.
1257: * <P>
1258: *
1259: * Each time a session is returned via this method, the session's last used
1260: * (referenced) time is updated to the current time.
1261: *
1262: * @param sessionKey
1263: * The String used to reference a <code>Session</code> object.
1264: * @return If the key is associated with an active session, then the
1265: * corresponding <code>Session</code> object is returned.
1266: * Otherwise <code>null</code> is returned.
1267: * @see Session
1268: * @see StandardSession#touch
1269: * @exception SessionException
1270: * If the session cannot be retrieved.
1271: */
1272: public synchronized Session getSession(String sessionKey)
1273: throws SessionException {
1274: keyGenerator.incrementRandomCounter();
1275: StandardSession session = (StandardSession) sessionHome
1276: .getSession(sessionKey);
1277: if (session != null) {
1278: session.touch();
1279: } else {
1280: sessionUserTable.remove(sessionKey);
1281: }
1282: return session;
1283: }
1284:
1285: /**
1286: * Lookup the <code>Session</code> object associated with the specified
1287: * session key.
1288: * <P>
1289: *
1290: * Each time a session is returned via this method, the session's last used
1291: * (referenced) time is updated to the current time.
1292: *
1293: * @param thread
1294: * the thread to associate with the session.
1295: * @param sessionKey
1296: * The String used to reference a <code>Session</code> object.
1297: * @return If the key is associated with an active session, then the
1298: * corresponding <code>Session</code> object is returned.
1299: * Otherwise <code>null</code> is returned.
1300: * @see Session
1301: * @see StandardSession#touch
1302: * @exception SessionException
1303: * If the session cannot be retrieved.
1304: */
1305: public synchronized Session getSession(Thread thread,
1306: String sessionKey) throws SessionException {
1307: keyGenerator.incrementRandomCounter();
1308: StandardSession session = (StandardSession) sessionHome
1309: .getSession(thread, sessionKey);
1310: if (session != null) {
1311: session.touch();
1312: } else {
1313: sessionUserTable.remove(sessionKey);
1314: }
1315: return session;
1316: }
1317:
1318: /**
1319: * Support for director connector Director connector sets header :affCR: ,
1320: * in that case we need to delete active session and create new one , with
1321: * new ipPortToken
1322: */
1323: public synchronized Session getSession(Thread thread,
1324: String sessionKey, HttpPresentationComms comms)
1325: throws SessionException {
1326:
1327: Session session = getSession(thread, sessionKey);
1328:
1329: // String saTokChangeRequest = null;
1330: /*
1331: * try{ saTokChangeRequest = comms.request.getHeader(":affCR:"); } catch
1332: * (HttpPresentationException hpe) { saTokChangeRequest=null; }
1333: */
1334: /*if (saTokChangeRequest != null && session != null) {
1335: deleteSession(session);
1336: return null;
1337: } else {
1338: return session;
1339: }*/
1340: return session;
1341: }
1342:
1343: /**
1344: * Lookup the <code>Session</code> object associated with the specified
1345: * session key.
1346: * <P>
1347: *
1348: * Each time a session is returned via this method, the session's last used
1349: * (referenced) time is NOT!!! updated to the current time.
1350: *
1351: * This method is for save reporting without change the last time used.
1352: *
1353: * @param thread
1354: * the thread to associate with the session.
1355: * @param sessionKey
1356: * The String used to reference a <code>Session</code> object.
1357: * @return If the key is associated with an active session, then the
1358: * corresponding <code>Session</code> object is returned.
1359: * Otherwise <code>null</code> is returned.
1360: * @see Session
1361: * @see StandardSession#touch
1362: * @exception SessionException
1363: * If the session cannot be retrieved.
1364: * @author schubi@die-schubis.de
1365: */
1366: public synchronized Session getSaveSession(Thread thread,
1367: String sessionKey) throws SessionException {
1368: keyGenerator.incrementRandomCounter();
1369: StandardSession session = (StandardSession) sessionHome
1370: .getSession(thread, sessionKey);
1371: if (session != null) {
1372: // session.touch();
1373: } else {
1374: sessionUserTable.remove(sessionKey);
1375: }
1376: return session;
1377: }
1378:
1379: /**
1380: * Get all of the active sessions.
1381: *
1382: * @return An enumeration of the active sessions.
1383: * @exception SessionException
1384: * If the sessions cannot be retrieved.
1385: */
1386: public synchronized Enumeration getSessionKeys()
1387: throws SessionException {
1388: return sessionHome.keys();
1389: }
1390:
1391: /**
1392: * Lookup the keys for the active sessions for a user. A given user may have
1393: * multiple sessions associated with it (using FTP as an example, the
1394: * "anonymous" account).
1395: *
1396: * @param user
1397: * The user to search for.
1398: * @return An enumeration containing the session keys of the active sessions
1399: * for the user.
1400: * @exception SessionException
1401: * If the sessions cannot be retrieved.
1402: */
1403: public synchronized Enumeration getSessionKeys(User user)
1404: throws SessionException {
1405: return sessionUserTable.getSessionKeys(user);
1406: }
1407:
1408: /**
1409: * Gets the number of currently active sessions.
1410: *
1411: * @return The number of currently active sessions.
1412: * @exception SessionException
1413: * If the session cannot be calculated.
1414: */
1415: public int activeSessionCount() throws SessionException {
1416: return sessionHome.size();
1417: }
1418:
1419: /**
1420: * Gets the number of session that are paged to persistent store.
1421: *
1422: * @return The number of currently paged sessions.
1423: * @exception SessionException
1424: * If the session cannot be calculated.
1425: */
1426: public int pagedSessionCount() throws SessionException {
1427: return sessionHome.pagedSize();
1428: }
1429:
1430: /**
1431: * Returns the current mode for the session manager.
1432: *
1433: * @return the mode.
1434: * @exception SessionException
1435: * If the mode cannot be determined.
1436: * @see #MODE_BASIC
1437: * @see #MODE_PAGE_TO_DISK
1438: * @see #MODE_PAGE_TO_DB
1439: * @see #MODE_CUSTOM
1440: */
1441: public int getMode() throws SessionException {
1442: return mode;
1443: }
1444:
1445: /**
1446: * Gets the maximum number of concurent sessions that existed at any time
1447: * since this object was created, or <CODE>resetMaxSessionCount()</CODE>
1448: * was called. This is a historical highwater mark.
1449: *
1450: * @return The highwater mark for number of sessions, or -1.
1451: */
1452: public int maxSessionCount() {
1453: return maxSessions;
1454: }
1455:
1456: /**
1457: * Gets the time when the maximum refered to by <CODE>maxSessionCount()</CODE>
1458: * occured.
1459: *
1460: * @return The Date of when the maximum number of sessions occured.
1461: */
1462: public Date maxSessionCountDate() {
1463: return maxSessionsDate;
1464: }
1465:
1466: /**
1467: * Reset the maximum session count. See <CODE>maxSessionCount()</CODE>.
1468: * The highwater mark should be reset to the current number of sessions.
1469: *
1470: * @exception SessionException
1471: * if the max session count cannot be reset.
1472: */
1473: public void resetMaxSessionCount() throws SessionException {
1474: maxSessions = sessionHome.size();
1475: maxSessionsDate = new Date();
1476: }
1477:
1478: /**
1479: * Returns the maximum session life time, in seconds.
1480: */
1481: public long getMaxSessionLifeTime() {
1482: return maxSessionLifeTime;
1483: }
1484:
1485: /**
1486: * Sets the maximum session idle time, in seconds.
1487: */
1488: public void setMaxSessionIdleTime(long maxSessionIdleTime) {
1489: this .maxSessionIdleTime = maxSessionIdleTime;
1490: }
1491:
1492: /**
1493: * Returns the maximum session idle time, in seconds.
1494: */
1495: public long getMaxSessionIdleTime() {
1496: return maxSessionIdleTime;
1497: }
1498:
1499: /**
1500: * Returns the url encoding state. Either <code>Never</code>
1501: * <code>Always</code> <code>Auto</code>
1502: */
1503: public String getEncodeUrlState() {
1504: return encodeUrlState;
1505: }
1506:
1507: /**
1508: * Returns the url encoding rule for the first application page
1509: * (true/false).
1510: *
1511: * CFG_ENCODE_URL_STATE must not be set to NEVER for this parameter to take
1512: * efect
1513: */
1514: public boolean getEncodeFirstUrl() {
1515: return encodeFirstUrl;
1516: }
1517:
1518: /**
1519: * Returns the maximum no-user session idle time, in seconds.
1520: */
1521: public long getMaxNoUserSessionIdleTime() {
1522: return maxNoUserSessionIdleTime;
1523: }
1524:
1525: /**
1526: * Prints debug information under Logger.DEBUG.
1527: *
1528: * @param level
1529: * the debug level.
1530: * @param msg
1531: * the message to print.
1532: */
1533: protected void debug(int level, String msg) {
1534: int dbg = Logger.DEBUG;
1535: switch (level) {
1536: case 1:
1537: dbg = Logger.DEBUG1;
1538: break;
1539: case 2:
1540: dbg = Logger.DEBUG2;
1541: break;
1542: case 3:
1543: dbg = Logger.DEBUG3;
1544: break;
1545: case 4:
1546: dbg = Logger.DEBUG4;
1547: break;
1548: case 5:
1549: dbg = Logger.DEBUG5;
1550: break;
1551: case 6:
1552: dbg = Logger.DEBUG6;
1553: break;
1554: case 7:
1555: dbg = Logger.DEBUG7;
1556: break;
1557: case 8:
1558: dbg = Logger.DEBUG8;
1559: break;
1560: case 9:
1561: dbg = Logger.DEBUG9;
1562: break;
1563: default:
1564: dbg = Logger.DEBUG;
1565: break;
1566: }
1567: Enhydra.getLogChannel().write(
1568: dbg,
1569: "PersistentSessionHome("
1570: + Thread.currentThread().getName() + "): "
1571: + msg);
1572: }
1573:
1574: /*
1575: * (non-Javadoc)
1576: * @see com.lutris.appserver.server.session.SessionManager#getEmptySessionPath()
1577: */
1578: public boolean getEmptySessionPath() {
1579: return emptySessionPath;
1580: }
1581: }
|