0001: /*
0002: * The contents of this file are subject to the
0003: * Mozilla Public License Version 1.1 (the "License");
0004: * you may not use this file except in compliance with the License.
0005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0006: *
0007: * Software distributed under the License is distributed on an "AS IS"
0008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
0009: * See the License for the specific language governing rights and
0010: * limitations under the License.
0011: *
0012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
0013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
0014: *
0015: * All Rights Reserved.
0016: *
0017: * Contributor(s):
0018: */
0019:
0020: package org.openharmonise.rm.sessions;
0021:
0022: import java.security.SecureRandom;
0023: import java.sql.*;
0024: import java.text.SimpleDateFormat;
0025: import java.util.List;
0026: import java.util.logging.*;
0027:
0028: import javax.servlet.http.HttpServletRequest;
0029:
0030: import org.openharmonise.commons.cache.*;
0031: import org.openharmonise.commons.dsi.*;
0032: import org.openharmonise.commons.dsi.dml.*;
0033: import org.openharmonise.rm.*;
0034: import org.openharmonise.rm.config.*;
0035: import org.openharmonise.rm.dsi.DataStoreObject;
0036: import org.openharmonise.rm.factory.*;
0037: import org.openharmonise.rm.logging.*;
0038: import org.openharmonise.rm.publishing.*;
0039: import org.openharmonise.rm.resources.AbstractObject;
0040: import org.openharmonise.rm.resources.publishing.Template;
0041: import org.openharmonise.rm.resources.users.User;
0042: import org.openharmonise.rm.security.authentication.*;
0043: import org.w3c.dom.*;
0044:
0045: /**
0046: * Represents a user session within the system, with an
0047: * associated timeout value.
0048: *
0049: * Through the implementation of <code>Publishable</code> a user
0050: * can log in and out, i.e. create and delete sessions, in a web
0051: * session.
0052: *
0053: * @author Michael Bell
0054: * @version $Revision: 1.3 $
0055: *
0056: */
0057: public class Session implements DataStoreObject, Publishable {
0058:
0059: //DB constants
0060: protected static final String CLMN_SESSION_ID = "id";
0061: protected static final String CLMN_SESSION_DATE = "date";
0062: protected static final String CLMN_SESSION_TIMEOUT = "timeout";
0063: protected static final String CLMN_USER_ID = "users_id";
0064: protected static final String CLMN_TYPE = "type";
0065: protected static final String TBL_SESSION = "session";
0066:
0067: //XML constants
0068: public static final String TAG_SESSION = "Session";
0069: public static final String TAG_LOGON = "Logon";
0070: public static final String TAG_LOGOFF = "Logoff";
0071:
0072: public static final String DEFAULT_TIMEOUT_PNAME = "DEFAULT_TIMEOUT";
0073: private static final int m_nDefaultNumChars = 20;
0074: private static final String sCharBase = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
0075: private static final String DB_DATEFORMAT = "MM-dd-yyyy HH:mm:ss.SSS";
0076: private AbstractDataStoreInterface m_dsi;
0077:
0078: public static String LAG_PERCENT_PNAME = "LAGTIME_PERCENT";
0079: public static String PREFIX_SEPARATOR = "_";
0080: public static String DEFAULT_USER_PREFIX = "D" + PREFIX_SEPARATOR;
0081: public static String LOGGED_IN_USER_PREFIX = "L" + PREFIX_SEPARATOR;
0082:
0083: protected CachePointer m_usrPtr = null;
0084: protected String m_sSessionId = "";
0085: protected java.util.Date m_dtTimeout;
0086: protected boolean m_bTimedOut = false;
0087: protected boolean m_bDefaultUser = true;
0088:
0089: //default to 1
0090: protected int DEFAULT_USER_ID = 1;
0091: protected int m_nTimeout = 60;
0092: protected int m_nLagPercent = -1;
0093: protected String sDefaultLagPercent = "25";
0094: protected java.util.Date m_dtLagTime;
0095:
0096: /**
0097: * Logger for this class
0098: */
0099: private static final Logger m_logger = Logger
0100: .getLogger(Session.class.getName());
0101:
0102: public static User m_QueryUser = null;
0103:
0104: static {
0105: m_QueryUser = new User();
0106: }
0107:
0108: /**
0109: * Constructs a new empty session.
0110: * @param dbinterf
0111: */
0112: public Session(AbstractDataStoreInterface dbinterf) {
0113: m_dsi = dbinterf;
0114: }
0115:
0116: /**
0117: * Standard constructor for a new <code>Session</code> object with the given data.
0118: *
0119: * @param dbinterf
0120: * @param usr
0121: * @param sessionId
0122: * @param timeout
0123: * @throws SessionException
0124: */
0125: public Session(AbstractDataStoreInterface dbinterf, User usr,
0126: String sessionId, int timeout) throws SessionException {
0127: m_dsi = dbinterf;
0128:
0129: try {
0130: m_usrPtr = CacheHandler.getInstance(dbinterf)
0131: .getCachePointer(usr);
0132: } catch (CacheException e) {
0133: throw new SessionException(e.getLocalizedMessage(), e);
0134: }
0135: this .m_sSessionId = sessionId;
0136:
0137: setTimeout(timeout);
0138: try {
0139: setLagTime(timeout);
0140: } catch (ConfigException e) {
0141: throw new SessionException(
0142: "Error occured setting lag time", e);
0143: }
0144:
0145: if (isSessionIdUnique(sessionId) == false) {
0146: m_logger.logp(Level.INFO, this .getClass().getName(),
0147: "Session", "Session id " + sessionId
0148: + " is not unique and therefore not valid");
0149: throw new InvalidSessionIdException("Invalid session id - "
0150: + sessionId);
0151: }
0152:
0153: save();
0154: }
0155:
0156: /**
0157: * Constructs a session from a known session id.
0158: * @param dbinterf
0159: * @param sSessionId
0160: */
0161: public Session(AbstractDataStoreInterface dbinterf,
0162: String sSessionId) throws SessionException {
0163: m_dsi = dbinterf;
0164:
0165: setDetailsFromId(sSessionId);
0166: }
0167:
0168: /**
0169: * Constructs a new sessio with the specified timeout.
0170: * with a default user.
0171: * @param dbinterf
0172: * @param timeout
0173: */
0174: public Session(AbstractDataStoreInterface dbinterf, int timeout)
0175: throws SessionException {
0176: m_dsi = dbinterf;
0177:
0178: User user = null;
0179: try {
0180: user = (User) HarmoniseObjectFactory
0181: .instantiateHarmoniseObject(dbinterf, User.class
0182: .getName(), DEFAULT_USER_ID);
0183: } catch (HarmoniseFactoryException e) {
0184: throw new SessionException(e);
0185: }
0186: initialize(user, timeout);
0187: }
0188:
0189: /**
0190: * Constructs a new session object for the given user and timeout.
0191: * @param dbinterf
0192: * @param user
0193: * @param timeout
0194: */
0195: public Session(AbstractDataStoreInterface dbinterf, User user,
0196: int timeout) throws SessionException {
0197: m_dsi = dbinterf;
0198: initialize(user, timeout);
0199: }
0200:
0201: /**
0202: * Removes session id prefix if found.
0203: * For example:<blockquote><pre>D_hHk1IsvRlfC1iksMH6lt becomes hHk1IsvRlfC1iksMH6lt</pre></blockquote>
0204: *
0205: * Note: Used to save session id in the database and cache.
0206: *
0207: * @param sSessId session id.
0208: * @return session id without prefix.
0209: */
0210: public static String removeSessionIdPrefix(String sSessId) {
0211: String newSessId = sSessId;
0212: int index = sSessId.indexOf(PREFIX_SEPARATOR);
0213:
0214: if (index > 0) {
0215: newSessId = sSessId.substring(index + 1);
0216: }
0217:
0218: return newSessId;
0219: }
0220:
0221: /**
0222: * Returns the id of this session.
0223: *
0224: * @return session id variable.
0225: */
0226: public String getSessionId() {
0227: return m_sSessionId;
0228: }
0229:
0230: /**
0231: * Returns the user associated with this session.
0232: *
0233: * @return User variable.
0234: */
0235: public User getUser() throws DataAccessException {
0236: User usr = null;
0237:
0238: try {
0239: usr = (User) m_usrPtr.getObject();
0240: } catch (CacheException e) {
0241: throw new DataAccessException(e.getLocalizedMessage(), e);
0242: }
0243:
0244: return usr;
0245: }
0246:
0247: /**
0248: * Register the servlet request with the session so the session has access to request info.
0249: */
0250: public void registerHttpRequest(HttpServletRequest request) {
0251:
0252: }
0253:
0254: /**
0255: * Gets session id from state and if found validates against object session id.
0256: * Checks for log off, switching session id prefix to default if logging off.
0257: * Updates timeout, throwing error if timed out unless default user.
0258: * Checks for log on, logging on user if found and switching session id prefix to logged on.
0259: * If no session id was found in the state, <code>initialize(user, nTimeout)</code> is called.
0260: * Otherwise, <code>updateUser(user)</code> is called.
0261: *
0262: * @exception SessionException
0263: * @param state
0264: * @param nTimeout
0265: */
0266: public void processState(State state, int nTimeout)
0267: throws SessionException {
0268: String sSessId = "";
0269: boolean bHasSessionId = false;
0270:
0271: if (state == null) {
0272: throw new SessionException("Null state object");
0273: }
0274:
0275: NodeList nodeSession = state.getElementsByTagName(TAG_SESSION);
0276:
0277: if (nodeSession.getLength() > 0) {
0278: // get the session id from the session tag, throw
0279: //exception if absent or different to current session id
0280: Element sessEl = (Element) nodeSession.item(0);
0281: sSessId = sessEl.getAttribute(AbstractObject.ATTRIB_ID);
0282:
0283: if ((sSessId.length() == 0) && (m_sSessionId.length() == 0)) {
0284: throw new InvalidSessionIdException(
0285: "Not found a Session Id");
0286: }
0287:
0288: if (sSessId.length() > 0) {
0289: if (!m_sSessionId.equals(sSessId)) {
0290: throw new InvalidSessionIdException(
0291: "Attempt to validate Session ID: "
0292: + sSessId + " against Session: "
0293: + m_sSessionId);
0294: }
0295: }
0296:
0297: bHasSessionId = true;
0298: }
0299:
0300: // check for logoff tag before checking timeout
0301: // never want logging off user to time out
0302: NodeList nodes = state.getElementsByTagName(TAG_LOGOFF);
0303:
0304: if (nodes.getLength() > 0) {
0305:
0306: try {
0307: logoff((Element) nodes.item(0), getSessionId());
0308: } catch (DataStoreException e) {
0309: throw new SessionException(
0310: "Error occured with log off", e);
0311: }
0312:
0313: //switch prefix to default user
0314: m_sSessionId = removeSessionIdPrefix(m_sSessionId);
0315: m_sSessionId = DEFAULT_USER_PREFIX + m_sSessionId;
0316: }
0317:
0318: if (bHasSessionId) {
0319: // update timeout, if timed out will throw exception unless default user
0320: updateTimeout(nTimeout);
0321: }
0322:
0323: // check for logon tag in state after checking timeout
0324: // so that logging in user switching from default user
0325: // will never time out
0326: boolean bIsLogOn = false;
0327: NodeList nodeLogOn = state.getElementsByTagName(TAG_LOGON);
0328:
0329: if (nodeLogOn.getLength() > 0) {
0330: bIsLogOn = true;
0331: }
0332:
0333: //user logging on
0334: if (bIsLogOn == true) {
0335:
0336: User user = logon((Element) nodeLogOn.item(0), state);
0337:
0338: if (bHasSessionId
0339: || (this .m_sSessionId != null && this .m_sSessionId
0340: .length() > 0)) {
0341: // user already has session so update
0342: try {
0343: updateUser(user);
0344: } catch (DataStoreException e) {
0345: throw new SessionException(
0346: "Error occured updating user", e);
0347: }
0348: } else {
0349: // create new session
0350: initialize(user, nTimeout);
0351:
0352: bHasSessionId = true;
0353: }
0354:
0355: //switch prefix to default user
0356: m_sSessionId = removeSessionIdPrefix(m_sSessionId);
0357: m_sSessionId = LOGGED_IN_USER_PREFIX + m_sSessionId;
0358:
0359: // set default user flag
0360: } else if (bHasSessionId == false
0361: && (this .m_sSessionId == null || this .m_sSessionId
0362: .length() == 0)) {
0363: // create new session for default user
0364:
0365: User user = getDefaultUser();
0366: sSessId = initialize(user, nTimeout);
0367:
0368: bHasSessionId = true;
0369: }
0370:
0371: }
0372:
0373: /**
0374: * Saves session id, user key and timeout values to database.
0375: *
0376: * @throws InvalidSessionIdException if there is no session id or user.
0377: */
0378: public void save() throws SessionException {
0379: ResultSet rs = null;
0380: InsertStatement insert = new InsertStatement();
0381:
0382: User usr = null;
0383:
0384: try {
0385: usr = getUser();
0386: } catch (DataAccessException e) {
0387: throw new SessionException(e.getLocalizedMessage(), e);
0388: }
0389:
0390: if ((m_sSessionId.length() > 0) && (usr != null)) {
0391: // insert this entry WITHOUT session id prefix
0392: try {
0393: insert.addColumnValue(
0394: getInstanceColumnRef(CLMN_SESSION_ID),
0395: removeSessionIdPrefix(m_sSessionId));
0396: insert
0397: .addColumnValue(
0398: getInstanceColumnRef(CLMN_USER_ID), usr
0399: .getId());
0400: insert.addColumnValue(
0401: getInstanceColumnRef(CLMN_SESSION_TIMEOUT),
0402: m_dtTimeout);
0403:
0404: m_dsi.execute(insert);
0405: } catch (DataStoreException e) {
0406:
0407: m_logger.log(Level.WARNING, e.getMessage(), e);
0408: throw new SessionException(
0409: "Error occured saving session", e);
0410: }
0411: } else {
0412: throw new InvalidSessionIdException("Error saving session");
0413: }
0414: }
0415:
0416: /**
0417: * Records an event.
0418: *
0419: * @param nEvent
0420: * @param sMessage
0421: * @param nTimeout
0422: * @throws SessionException
0423: * @deprecated
0424: */
0425: public void recordEvent(LogEvent event) throws SessionException {
0426: try {
0427: event.setSession(this );
0428:
0429: EventLogController.getInstance().logEvent(event);
0430: } catch (LogException e) {
0431: throw new SessionException("Error logging event", e);
0432: }
0433:
0434: }
0435:
0436: /**
0437: * Generates a SessionId with default number of characters.
0438: *
0439: * @return int the session id generated
0440: */
0441: public static String generateSessionId() {
0442: return (generateSessionId(m_nDefaultNumChars));
0443: }
0444:
0445: /* (non-Javadoc)
0446: * @see java.lang.Object#toString()
0447: */
0448: public String toString() {
0449: StringBuffer strbuf = new StringBuffer();
0450: SimpleDateFormat formatter = new SimpleDateFormat(DB_DATEFORMAT);
0451:
0452: try {
0453: strbuf.append(" [").append("Session_id:").append(
0454: m_sSessionId).append(" for user_id:").append(
0455: m_usrPtr.getKey()).append(", timeout:").append(
0456: (m_dtTimeout != null) ? formatter
0457: .format(m_dtTimeout) : "null").append(
0458: ", Timed Out?:").append(m_bTimedOut).append(
0459: ", lagtime:").append(
0460: (m_dtLagTime != null) ? formatter
0461: .format(m_dtLagTime) : "null").append(
0462: ", Lag timed out?:").append(isLagTimedOut())
0463: .append(" ]");
0464: } catch (Exception e) {
0465: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
0466: }
0467:
0468: return strbuf.toString();
0469: }
0470:
0471: /**
0472: * Removes session from the database and cache.
0473: *
0474: * @throws SessionException
0475: */
0476: public void delete() throws SessionException {
0477:
0478: try {
0479: DeleteStatement delete = new DeleteStatement();
0480: ColumnRef crSessId = new Session(m_dsi)
0481: .getInstanceColumnRef(CLMN_SESSION_ID);
0482: delete.addWhereCondition(crSessId, "=", m_sSessionId);
0483: m_dsi.execute(delete);
0484:
0485: WebPageEngineCache.getInstance(m_dsi).changeObject(
0486: m_sSessionId, AbstractCache.CHANGE_DELETE, this );
0487: } catch (DataStoreException e) {
0488: throw new SessionException(
0489: "Error occured deleting from DB", e);
0490: } catch (CacheException e) {
0491: throw new SessionException(
0492: "Error getting webpage engine cache", e);
0493: }
0494: }
0495:
0496: /* (non-Javadoc)
0497: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceColumnRef(java.lang.String, boolean)
0498: */
0499: public ColumnRef getInstanceColumnRef(String sColumn,
0500: boolean bIsHist) throws DataStoreException {
0501: return getInstanceColumnRef(sColumn);
0502: }
0503:
0504: /* (non-Javadoc)
0505: * @see org.openharmonise.rm.dsi.DataStoreObject#getInstanceJoinConditions(java.lang.String, boolean)
0506: */
0507: public JoinConditions getInstanceJoinConditions(String sObjectTag,
0508: boolean bIsOuter) throws DataStoreException {
0509: // nothing to do
0510: return null;
0511: }
0512:
0513: /* (non-Javadoc)
0514: * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement)
0515: */
0516: public List processResultSet(CachedResultSet resultSet,
0517: SelectStatement select) {
0518: //nothing to do
0519: return null;
0520: }
0521:
0522: /* (non-Javadoc)
0523: * @see org.openharmonise.rm.dsi.DataStoreObject#processResultSet(org.openharmonise.commons.dsi.CachedResultSet, org.openharmonise.commons.dsi.dml.SelectStatement, int)
0524: */
0525: public List processResultSet(CachedResultSet resultSet,
0526: SelectStatement select, int limit) {
0527: // nothing to do
0528: return null;
0529: }
0530:
0531: /* (non-Javadoc)
0532: * @see org.openharmonise.rm.dsi.DataStoreObject#getDBTableName()
0533: */
0534: public String getDBTableName() {
0535: return TBL_SESSION;
0536: }
0537:
0538: /**
0539: * Returns a Session tag with a session id attribute.
0540: *
0541: * @param output
0542: * @param state
0543: * @return
0544: * @throws PublishException
0545: */
0546: public Element publish(HarmoniseOutput output)
0547: throws PublishException {
0548: Element xnSession = output.createElement(TAG_SESSION);
0549: xnSession
0550: .setAttribute(AbstractObject.ATTRIB_ID, getSessionId());
0551:
0552: return xnSession;
0553: }
0554:
0555: /* (non-Javadoc)
0556: * @see org.openharmonise.rm.publishing.Publishable#publish(org.openharmonise.rm.resources.publishing.Template, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
0557: */
0558: public Element publish(Template template, HarmoniseOutput output,
0559: State state) throws PublishException {
0560: Element resultEl = null;
0561:
0562: try {
0563:
0564: resultEl = publish(template.getTemplateRootElement(),
0565: output, state);
0566: } catch (DataAccessException e) {
0567: throw new PublishException(e);
0568: }
0569:
0570: return resultEl;
0571: }
0572:
0573: /* (non-Javadoc)
0574: * @see org.openharmonise.rm.publishing.Publishable#publish(org.w3c.dom.Element, org.openharmonise.rm.publishing.HarmoniseOutput, org.openharmonise.rm.publishing.State)
0575: */
0576: public Element publish(Element topEl, HarmoniseOutput output,
0577: State state) throws PublishException {
0578: Element xnSession = output.createElement(TAG_SESSION);
0579: xnSession
0580: .setAttribute(AbstractObject.ATTRIB_ID, getSessionId());
0581:
0582: return xnSession;
0583: }
0584:
0585: /* (non-Javadoc)
0586: * @see org.openharmonise.rm.publishing.Publishable#populate(org.w3c.dom.Element, org.openharmonise.rm.publishing.State)
0587: */
0588: public void populate(Element xmlElement, State state)
0589: throws PopulateException {
0590: if (xmlElement.getTagName().equals(TAG_SESSION)) {
0591: m_sSessionId = xmlElement
0592: .getAttribute(AbstractObject.ATTRIB_ID);
0593: }
0594:
0595: }
0596:
0597: /* (non-Javadoc)
0598: * @see org.openharmonise.rm.publishing.Publishable#getTagName()
0599: */
0600: public String getTagName() {
0601: return TAG_SESSION;
0602: }
0603:
0604: /* (non-Javadoc)
0605: * @see org.openharmonise.rm.dsi.DataStoreObject#getId()
0606: */
0607: public int getId() {
0608: //int id not applicable
0609: return -1;
0610: }
0611:
0612: /*----------------------------------------------------------------------------
0613: Protected Functions
0614: -----------------------------------------------------------------------------*/
0615:
0616: /**
0617: * Tries to log on and return the user with username and password
0618: * found in the state. Sets default user flag to false.
0619: *
0620: * @param logon
0621: * @param state
0622: * @return User
0623: * @throws SessionException
0624: */
0625: protected User logon(Element logon, State state)
0626: throws SessionException {
0627: String sName = "";
0628: String sPassword = "";
0629:
0630: //find user element
0631: Element userEl = (Element) logon.getElementsByTagName(
0632: User.TAG_USER).item(0);
0633:
0634: //get node list from user element to find name and pwd
0635: NodeList nodes = userEl.getChildNodes();
0636:
0637: for (int i = 0; i < nodes.getLength(); i++) {
0638: Element el = (Element) nodes.item(i);
0639:
0640: if (el.getTagName().equals(User.TAG_NAME)) {
0641: sName = el.getFirstChild().getNodeValue();
0642: } else if (el.getTagName().equals(User.TAG_PASSWORD)) {
0643: sPassword = el.getFirstChild().getNodeValue();
0644: }
0645: }
0646:
0647: User user = null;
0648: try {
0649: // user = new User(m_dsi, sName, sPassword);
0650: UserAuthenticator authenticator = UserAuthenticatorFactory
0651: .getAuthenticator();
0652: user = authenticator.getUser(sName, sPassword);
0653:
0654: int nId = user.getId();
0655: user = (User) HarmoniseObjectFactory
0656: .instantiatePublishableObject(m_dsi, new User()
0657: .getClass().getName(), nId);
0658: } catch (HarmoniseFactoryException e) {
0659: throw new SessionException(
0660: "Error occured getting user from factory", e);
0661: } catch (UserAuthenticationException e) {
0662: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
0663: }
0664:
0665: setDefaultUser(false);
0666:
0667: return user;
0668: }
0669:
0670: /**
0671: * Compares timeout variable against current time, removing session from
0672: * database if true.
0673: *
0674: * @return true or false.
0675: * @throws SessionException
0676: */
0677: protected boolean isTimedOut() throws SessionException {
0678:
0679: java.util.Date dtNow = new java.util.Date();
0680:
0681: if (m_dtTimeout == null) {
0682: throw new RuntimeException("Timeout is null for this user "
0683: + this );
0684: }
0685:
0686: if (dtNow.after(m_dtTimeout)) {
0687:
0688: DeleteStatement delete = new DeleteStatement();
0689:
0690: //remove session from database.
0691: delete();
0692:
0693: m_bTimedOut = true;
0694: m_sSessionId = "";
0695: }
0696:
0697: return m_bTimedOut;
0698: }
0699:
0700: /**
0701: * Returns a <code>ColumnRef</code> corresponding to the column given.
0702: *
0703: * @param sColumn
0704: * @return
0705: * @throws DataStoreException
0706: */
0707: protected ColumnRef getInstanceColumnRef(String sColumn)
0708: throws DataStoreException {
0709: ColumnRef returnColRef = null;
0710:
0711: if (sColumn.equals(CLMN_SESSION_ID)) {
0712: return new ColumnRef(TBL_SESSION, CLMN_SESSION_ID,
0713: ColumnRef.TEXT);
0714: } else if (sColumn.equals(CLMN_USER_ID)) {
0715: return new ColumnRef(TBL_SESSION, CLMN_USER_ID,
0716: ColumnRef.NUMBER);
0717: } else if (sColumn.equals(CLMN_SESSION_TIMEOUT)) {
0718: return new ColumnRef(TBL_SESSION, CLMN_SESSION_TIMEOUT,
0719: ColumnRef.DATE);
0720: } else if (sColumn.equals(CLMN_SESSION_DATE)) {
0721: return new ColumnRef(TBL_SESSION, CLMN_SESSION_DATE,
0722: ColumnRef.DATE);
0723: } else if (sColumn.equals(CLMN_TYPE)) {
0724: return new ColumnRef(TBL_SESSION, CLMN_TYPE, ColumnRef.DATE);
0725: }
0726:
0727: if (returnColRef != null) {
0728: return returnColRef;
0729: } else {
0730: throw new InvalidColumnReferenceException(
0731: "No column of the name [" + sColumn
0732: + "] in Session");
0733: }
0734: }
0735:
0736: /**
0737: * Tests whether the <code>User</code> associated with this <code>Session</code>
0738: * is the system default <code>User</code>.
0739: *
0740: * @return true or false.
0741: */
0742: protected boolean isDefaultUser() {
0743: return m_bDefaultUser;
0744: }
0745:
0746: /**
0747: * Sets default user boolean.
0748: *
0749: * @param defaultUser true or false.
0750: */
0751: protected void setDefaultUser(boolean defaultUser) {
0752: m_bDefaultUser = defaultUser;
0753: }
0754:
0755: /**
0756: * Fills timeout variable by adding timeout to the current time.
0757: *
0758: * @param nTimeout timeout in minutes.
0759: */
0760: protected void setTimeout(int nTimeout) {
0761: m_nTimeout = nTimeout;
0762:
0763: //fill timeout variable
0764: java.util.Date dtNow = new java.util.Date();
0765: m_dtTimeout = new java.util.Date(dtNow.getTime()
0766: + (m_nTimeout * 60 * 1000));
0767: }
0768:
0769: /**
0770: * Fills lag time variable by calling <code>calculateLagTime(nTimeout)</code>
0771: * and adding this value to the current time.
0772: *
0773: * @param nTimeout timeout in minutes.
0774: * @throws ConfigException
0775: */
0776: protected void setLagTime(int nTimeout) throws ConfigException {
0777: //fill lagtime variable
0778: java.util.Date dtNow = new java.util.Date();
0779: m_dtLagTime = new java.util.Date(dtNow.getTime()
0780: + calculateLagTime(nTimeout));
0781: }
0782:
0783: /**
0784: * Populates session details from database.
0785: *
0786: * @param sSessId
0787: * @throws SessionException
0788: */
0789: protected void setDetailsFromId(String sSessId)
0790: throws SessionException {
0791: ResultSet rs = null;
0792:
0793: if (sSessId == null || sSessId.length() == 0) {
0794: if (m_logger.isLoggable(Level.INFO)) {
0795: m_logger
0796: .logp(Level.INFO, this .getClass().getName(),
0797: "setDetailFromId",
0798: "Invalid session id to process; null value or length = 0");
0799: }
0800: throw new InvalidSessionIdException();
0801: }
0802:
0803: SelectStatement select = new SelectStatement();
0804:
0805: try {
0806: select.addSelectColumn(getInstanceColumnRef(CLMN_USER_ID));
0807: select
0808: .addSelectColumn(getInstanceColumnRef(CLMN_SESSION_TIMEOUT));
0809:
0810: select.addWhereCondition(
0811: getInstanceColumnRef(CLMN_SESSION_ID), "=",
0812: removeSessionIdPrefix(sSessId));
0813: } catch (DataStoreException e) {
0814: m_logger.log(Level.WARNING,
0815: "Error occured building query to populate session "
0816: + sSessId, e);
0817: throw new SessionException("Error occured building query",
0818: e);
0819: }
0820:
0821: try {
0822:
0823: rs = m_dsi.execute(select);
0824:
0825: if (rs.next()) {
0826:
0827: User usr = (User) HarmoniseObjectFactory
0828: .instantiatePublishableObject(m_dsi,
0829: m_QueryUser.getClass().getName(), rs
0830: .getInt(1));
0831:
0832: if (usr == null || usr.exists() == false) {
0833:
0834: DeleteStatement delete = new DeleteStatement();
0835:
0836: delete.addWhereCondition(
0837: getInstanceColumnRef(CLMN_SESSION_ID), "=",
0838: removeSessionIdPrefix(sSessId));
0839:
0840: m_dsi.execute(delete);
0841:
0842: throw new InvalidSessionIdException();
0843: }
0844:
0845: m_usrPtr = CacheHandler.getInstance(m_dsi)
0846: .getCachePointer(usr);
0847: m_dtTimeout = rs.getTimestamp(2);
0848:
0849: int timeout = Integer.parseInt(ConfigSettings
0850: .getProperty(Session.DEFAULT_TIMEOUT_PNAME));
0851: setLagTime(timeout);
0852: m_sSessionId = sSessId;
0853: } else {
0854: int index = sSessId.indexOf(DEFAULT_USER_PREFIX);
0855:
0856: if (index > -1) {
0857:
0858: m_sSessionId = sSessId;
0859:
0860: int timeout = Integer
0861: .parseInt(ConfigSettings
0862: .getProperty(Session.DEFAULT_TIMEOUT_PNAME));
0863: initialize(getDefaultUser(), timeout);
0864: } else {
0865: if (m_logger.isLoggable(Level.INFO)) {
0866: m_logger.logp(Level.INFO, this .getClass()
0867: .getName(), "setDetailFromId",
0868: "Session " + sSessId + " is not valid");
0869: }
0870: throw new InvalidSessionIdException();
0871: }
0872: }
0873: } catch (SQLException e) {
0874: throw new SessionException("SQL exception", e);
0875: } catch (NumberFormatException e) {
0876: throw new SessionException("Error parsing default timeout",
0877: e);
0878: } catch (ConfigException e) {
0879: throw new SessionException("Error getting config setting",
0880: e);
0881: } catch (HarmoniseFactoryException e) {
0882: throw new SessionException(
0883: "Error getting user from factory", e);
0884: } catch (DataStoreException e) {
0885: m_logger.log(Level.WARNING, e.getMessage(), e);
0886: throw new SessionException("Error processing query", e);
0887: } catch (CacheException e) {
0888: throw new SessionException(e.getLocalizedMessage(), e);
0889: } finally {
0890: if (rs != null) {
0891: try {
0892: rs.close();
0893: } catch (SQLException e) {
0894: throw new SessionException(
0895: "Error closing result set", e);
0896: }
0897: }
0898: }
0899: }
0900:
0901: /**
0902: * Checks timeout for session. Calls <code>updateSession()</code> if ok.
0903: *
0904: * @throws SessionException if timed out, unless default user
0905: */
0906: protected void updateTimeout(int nTimeout) throws SessionException {
0907: if (!isDefaultUser() && isTimedOut()) {
0908: if (m_logger.isLoggable(Level.INFO)) {
0909: m_logger.info("Session " + m_sSessionId + " timed out");
0910: }
0911:
0912: throw new SessionTimeOutException("Session: "
0913: + this .m_sSessionId);
0914: } else {
0915:
0916: m_nTimeout = nTimeout;
0917:
0918: java.util.Date dtNow = new java.util.Date();
0919: m_dtTimeout = new java.util.Date(dtNow.getTime()
0920: + (m_nTimeout * 60 * 1000));
0921:
0922: try {
0923: updateSession();
0924: } catch (ConfigException e) {
0925: throw new SessionException(
0926: "Error occured accessig config setting", e);
0927: } catch (DataStoreException e) {
0928: throw new SessionException(
0929: "Error occured updating session", e);
0930: }
0931:
0932: }
0933: }
0934:
0935: /**
0936: * Attempts to log off user. Resets session user as default user.
0937: *
0938: * @param logoff_tag
0939: * @param sessId
0940: * @return true if successful.
0941: * @throws DataStoreException
0942: */
0943: protected boolean logoff(Element logoff_tag, String sessId)
0944: throws DataStoreException {
0945:
0946: if (m_logger.isLoggable(Level.FINE)) {
0947: m_logger.logp(Level.FINE, this .getClass().getName(),
0948: "logoff", "Loging off session " + sessId);
0949: }
0950:
0951: // let the logoff happen to the session_id passed, if there
0952: // is no session id defined within the logoff tag.
0953: // Prefer to use the session_id within the tag
0954: NodeList nodes = logoff_tag.getChildNodes();
0955:
0956: for (int i = 0; i < nodes.getLength(); i++) {
0957: Element el = (Element) nodes.item(i);
0958:
0959: if (el.getTagName().equals(TAG_SESSION)) {
0960: sessId = el.getAttribute(AbstractObject.ATTRIB_ID);
0961: }
0962: }
0963:
0964: if (sessId.length() == 0) {
0965: if (m_logger.isLoggable(Level.SEVERE)) {
0966: m_logger.logp(Level.SEVERE, this .getClass().getName(),
0967: "logoff", "Invalid session to log off - ["
0968: + sessId + "]");
0969: }
0970: throw new RuntimeException(
0971: "Attempt to log off without a valid session id"
0972: + ", session id:" + sessId);
0973: }
0974:
0975: //reset user in session to default user
0976: User user = getDefaultUser();
0977: updateUser(user);
0978: setDefaultUser(true);
0979:
0980: return true;
0981: }
0982:
0983: /**
0984: * Retrieves lag percent set in harmonise.prop file.
0985: *
0986: * @return lag percent
0987: * @throws ConfigException
0988: */
0989: protected int getLagPercent() throws ConfigException {
0990: if (m_nLagPercent < 0) {
0991: m_nLagPercent = ConfigSettings.getIntProperty(
0992: LAG_PERCENT_PNAME, sDefaultLagPercent);
0993: }
0994:
0995: return m_nLagPercent;
0996: }
0997:
0998: /**
0999: * Calls <code>getLagPercent()</code> to calculate lagtime as a percentage of timeout.
1000: *
1001: * @param timeout
1002: * @return lagtime lagtime in minutes.
1003: * @throws ConfigException
1004: */
1005: protected int calculateLagTime(int timeout) throws ConfigException {
1006: int lagtime = (timeout * 60 * 1000 * getLagPercent()) / 100;
1007:
1008: return lagtime;
1009: }
1010:
1011: /**
1012: * Checks lagtime against current time.
1013: *
1014: * @return
1015: */
1016: protected boolean isLagTimedOut() {
1017: boolean lagTimedOut = false;
1018:
1019: java.util.Date dtNow = new java.util.Date();
1020:
1021: if (dtNow.after(m_dtLagTime)) {
1022: lagTimedOut = true;
1023: }
1024:
1025: return lagTimedOut;
1026: }
1027:
1028: /**
1029: * Sets User member variable to user passed in.
1030: * Calls <code>updateDataBase()</code>.
1031: *
1032: * @param user
1033: * @throws DataStoreException
1034: */
1035: protected void updateUser(User user) throws DataStoreException {
1036:
1037: try {
1038: m_usrPtr = CacheHandler.getInstance(m_dsi).getCachePointer(
1039: user);
1040: } catch (CacheException e) {
1041: throw new DataStoreException(e.getLocalizedMessage(), e);
1042: }
1043:
1044: updateDataBase();
1045: }
1046:
1047: /*----------------------------------------------------------------------------
1048: Private Functions
1049: -----------------------------------------------------------------------------*/
1050:
1051: /**
1052: * Calls <code>updateDataBase()</code> if lagtime is exceeded.
1053: * Otherwise does nothing.
1054: *
1055: * @throws ConfigException
1056: * @throws DataStoreException
1057: */
1058: private void updateSession() throws ConfigException,
1059: DataStoreException {
1060: if (isLagTimedOut()) {
1061: updateDataBase();
1062:
1063: java.util.Date dtNow = new java.util.Date();
1064: m_dtLagTime = new java.util.Date(dtNow.getTime()
1065: + calculateLagTime(m_nTimeout));
1066: }
1067: }
1068:
1069: /**
1070: * Writes User, timeout and session id to the database.
1071: *
1072: * @throws DataStoreException
1073: */
1074: private void updateDataBase() throws DataStoreException {
1075: UpdateStatement update = new UpdateStatement();
1076:
1077: User usr = null;
1078: try {
1079: usr = (User) m_usrPtr.getObject();
1080: } catch (CacheException e) {
1081: throw new DataStoreException(e.getLocalizedMessage(), e);
1082: }
1083:
1084: update.addColumnValue(getInstanceColumnRef(CLMN_USER_ID), usr
1085: .getId());
1086: update
1087: .addColumnValue(
1088: getInstanceColumnRef(CLMN_SESSION_TIMEOUT),
1089: m_dtTimeout);
1090: update.addWhereCondition(getInstanceColumnRef(CLMN_SESSION_ID),
1091: "=", removeSessionIdPrefix(m_sSessionId));
1092:
1093: m_dsi.execute(update);
1094:
1095: }
1096:
1097: /**
1098: * Generates a SessionId.
1099: *
1100: * @param nNumChars number of characters in session id.
1101: * @return
1102: */
1103: private static String generateSessionId(int nNumChars) {
1104: String sSession = "";
1105: SecureRandom rnd = new SecureRandom();
1106: StringBuffer buffer = new StringBuffer();
1107:
1108: for (int i = 0; i < nNumChars; i++) {
1109: int nIndex = (int) (rnd.nextDouble() * (sCharBase.length() - 1));
1110: buffer.append(sCharBase.charAt(nIndex));
1111: }
1112:
1113: sSession = buffer.toString();
1114:
1115: return sSession;
1116: }
1117:
1118: /**
1119: * Checks to see whether this Session id is unique.
1120: *
1121: * @param sSessId
1122: * @return
1123: * @throws SessionException
1124: */
1125: private boolean isSessionIdUnique(String sSessId)
1126: throws SessionException {
1127: ResultSet rs = null;
1128: boolean bIsUnique = true;
1129:
1130: try {
1131: SelectStatement select = new SelectStatement();
1132: select
1133: .addSelectColumn(getInstanceColumnRef(CLMN_SESSION_ID));
1134: select
1135: .addWhereCondition(
1136: getInstanceColumnRef(CLMN_SESSION_ID), "=",
1137: sSessId);
1138:
1139: String temp = m_dsi.getSelectStatement(select);
1140: rs = m_dsi.executeQuery(select);
1141:
1142: if (rs.next()) {
1143: bIsUnique = false;
1144: }
1145: } catch (DataStoreException e) {
1146: throw new SessionException("Error occured on query", e);
1147: } catch (SQLException e) {
1148: throw new SessionException("Error occured on query", e);
1149: } finally {
1150: if (rs != null) {
1151: try {
1152: rs.close();
1153: } catch (SQLException e) {
1154: throw new SessionException(
1155: "Error occured closing result set", e);
1156: }
1157: }
1158: }
1159:
1160: return bIsUnique;
1161: }
1162:
1163: /**
1164: * Removes all session entries for a user from the database.
1165: *
1166: * @param userKey
1167: * @throws SessionException
1168: */
1169: private void removeAllSessionEntries(int userKey)
1170: throws SessionException {
1171: DeleteStatement delete = null;
1172:
1173: try {
1174: delete = new DeleteStatement();
1175: delete.setTable(TBL_SESSION);
1176: delete.addWhereCondition(
1177: getInstanceColumnRef(CLMN_USER_ID), "=", userKey);
1178:
1179: m_dsi.execute(delete);
1180: } catch (DataStoreException e) {
1181: throw new SessionException("Error removing sessions", e);
1182: }
1183: }
1184:
1185: /**
1186: * Constructs a default user.
1187: *
1188: * @return default user.
1189: */
1190: private User getDefaultUser() {
1191: User user = new User(m_dsi, DEFAULT_USER_ID);
1192:
1193: return user;
1194: }
1195:
1196: /**
1197: * Sets user, timeout and lagtime variables. Updates session id prefix, creating
1198: * new session id if there isn't one. Calls <code>save()</code>.
1199: *
1200: * @param user User of session, may be default or logged in.
1201: * @param nTimeout timeout in minutes.
1202: * @return session id.
1203: * @throws SessionException
1204: */
1205: private String initialize(User user, int nTimeout)
1206: throws SessionException {
1207:
1208: try {
1209: m_usrPtr = CacheHandler.getInstance(m_dsi).getCachePointer(
1210: user);
1211: } catch (CacheException e) {
1212: throw new SessionException(e.getLocalizedMessage(), e);
1213: }
1214:
1215: setTimeout(nTimeout);
1216: try {
1217: setLagTime(nTimeout);
1218: } catch (ConfigException e) {
1219: throw new SessionException("Error setting lag time", e);
1220: }
1221:
1222: String sSessId = "";
1223:
1224: if (m_sSessionId.equals("") == true) {
1225: sSessId = generateSessionId();
1226: } else {
1227: sSessId = removeSessionIdPrefix(m_sSessionId);
1228: }
1229:
1230: while (!isSessionIdUnique(sSessId)) {
1231: sSessId = generateSessionId();
1232: }
1233:
1234: int userId = user.getId();
1235:
1236: // first clear out any other session ids, unless default user
1237: //add prefix for default/logged in user
1238: if (userId != this.DEFAULT_USER_ID) {
1239: m_sSessionId = LOGGED_IN_USER_PREFIX + sSessId;
1240: removeAllSessionEntries(userId);
1241: } else {
1242: m_sSessionId = DEFAULT_USER_PREFIX + sSessId;
1243: }
1244:
1245: save();
1246:
1247: return m_sSessionId;
1248: }
1249:
1250: }
|