0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/event/tags/sakai_2-4-1/event-impl/impl/src/java/org/sakaiproject/event/impl/UsageSessionServiceAdaptor.java $
0003: * $Id: UsageSessionServiceAdaptor.java 15113 2006-09-21 19:11:42Z ggolden@umich.edu $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.sakaiproject.event.impl;
0021:
0022: import java.sql.ResultSet;
0023: import java.sql.SQLException;
0024: import java.util.Collection;
0025: import java.util.Enumeration;
0026: import java.util.Iterator;
0027: import java.util.List;
0028: import java.util.Map;
0029: import java.util.Set;
0030: import java.util.TreeMap;
0031: import java.util.Vector;
0032:
0033: import javax.servlet.http.HttpServletRequest;
0034:
0035: import org.apache.commons.logging.Log;
0036: import org.apache.commons.logging.LogFactory;
0037: import org.sakaiproject.authz.api.AuthzGroupService;
0038: import org.sakaiproject.component.api.ServerConfigurationService;
0039: import org.sakaiproject.db.api.SqlReader;
0040: import org.sakaiproject.db.api.SqlService;
0041: import org.sakaiproject.event.api.EventTrackingService;
0042: import org.sakaiproject.event.api.SessionState;
0043: import org.sakaiproject.event.api.SessionStateBindingListener;
0044: import org.sakaiproject.event.api.UsageSession;
0045: import org.sakaiproject.event.api.UsageSessionService;
0046: import org.sakaiproject.id.api.IdManager;
0047: import org.sakaiproject.thread_local.api.ThreadLocalManager;
0048: import org.sakaiproject.time.api.Time;
0049: import org.sakaiproject.time.api.TimeService;
0050: import org.sakaiproject.tool.api.Session;
0051: import org.sakaiproject.tool.api.SessionBindingEvent;
0052: import org.sakaiproject.tool.api.SessionBindingListener;
0053: import org.sakaiproject.tool.api.SessionManager;
0054: import org.sakaiproject.tool.api.ToolSession;
0055: import org.sakaiproject.user.api.Authentication;
0056: import org.sakaiproject.user.api.User;
0057: import org.sakaiproject.user.api.UserDirectoryService;
0058: import org.sakaiproject.user.api.UserNotDefinedException;
0059:
0060: /**
0061: * <p>
0062: * UsageSessionServiceAdaptor implements the UsageSessionService. The Session aspects are done as an adaptor to the SessionManager. UsageSession entities are handled as was in the ClusterUsageSessionService.
0063: * </p>
0064: */
0065: public abstract class UsageSessionServiceAdaptor implements
0066: UsageSessionService {
0067: /** Our log (commons). */
0068: private static Log M_log = LogFactory
0069: .getLog(UsageSessionServiceAdaptor.class);
0070:
0071: /** Storage manager for this service. */
0072: protected Storage m_storage = null;
0073:
0074: /**********************************************************************************************************************************************************************************************************************************************************
0075: * Abstractions, etc.
0076: *********************************************************************************************************************************************************************************************************************************************************/
0077:
0078: /**
0079: * Construct storage for this service.
0080: */
0081: protected Storage newStorage() {
0082: return new ClusterStorage();
0083: }
0084:
0085: /**********************************************************************************************************************************************************************************************************************************************************
0086: * Dependencies
0087: *********************************************************************************************************************************************************************************************************************************************************/
0088:
0089: /**
0090: * @return the TimeService collaborator.
0091: */
0092: protected abstract TimeService timeService();
0093:
0094: /** Dependency: SqlService. */
0095: /**
0096: * @return the SqlService collaborator.
0097: */
0098: protected abstract SqlService sqlService();
0099:
0100: /**
0101: * @return the ServerConfigurationService collaborator.
0102: */
0103: protected abstract ServerConfigurationService serverConfigurationService();
0104:
0105: /**
0106: * @return the ThreadLocalManager collaborator.
0107: */
0108: protected abstract ThreadLocalManager threadLocalManager();
0109:
0110: /**
0111: * @return the SessionManager collaborator.
0112: */
0113: protected abstract SessionManager sessionManager();
0114:
0115: /**
0116: * @return the IdManager collaborator.
0117: */
0118: protected abstract IdManager idManager();
0119:
0120: /**
0121: * @return the EventTrackingService collaborator.
0122: */
0123: protected abstract EventTrackingService eventTrackingService();
0124:
0125: /**
0126: * @return the AuthzGroupService collaborator.
0127: */
0128: protected abstract AuthzGroupService authzGroupService();
0129:
0130: /**
0131: * @return the UserDirectoryService collaborator.
0132: */
0133: protected abstract UserDirectoryService userDirectoryService();
0134:
0135: /**********************************************************************************************************************************************************************************************************************************************************
0136: * Configuration
0137: *********************************************************************************************************************************************************************************************************************************************************/
0138:
0139: /** Configuration: to run the ddl on init or not. */
0140: protected boolean m_autoDdl = false;
0141:
0142: /**
0143: * Configuration: to run the ddl on init or not.
0144: *
0145: * @param value
0146: * the auto ddl value.
0147: */
0148: public void setAutoDdl(String value) {
0149: m_autoDdl = new Boolean(value).booleanValue();
0150: }
0151:
0152: /**********************************************************************************************************************************************************************************************************************************************************
0153: * Init and Destroy
0154: *********************************************************************************************************************************************************************************************************************************************************/
0155:
0156: public UsageSessionServiceAdaptor() {
0157: m_storage = newStorage();
0158: }
0159:
0160: /**
0161: * Final initialization, once all dependencies are set.
0162: */
0163: public void init() {
0164: try {
0165: // open storage
0166: m_storage.open();
0167:
0168: M_log.info("init()");
0169: } catch (Throwable t) {
0170: M_log.warn("init(): ", t);
0171: }
0172: }
0173:
0174: /**
0175: * Returns to uninitialized state.
0176: */
0177: public void destroy() {
0178: m_storage.close();
0179:
0180: M_log.info("destroy()");
0181: }
0182:
0183: /**********************************************************************************************************************************************************************************************************************************************************
0184: * UsageSessionService implementation
0185: *********************************************************************************************************************************************************************************************************************************************************/
0186:
0187: /**
0188: * @inheritDoc
0189: */
0190: public UsageSession startSession(String userId,
0191: String remoteAddress, String userAgent) {
0192: // do we have a current session?
0193: Session s = sessionManager().getCurrentSession();
0194: if (s != null) {
0195: UsageSession session = (UsageSession) s
0196: .getAttribute(USAGE_SESSION_KEY);
0197: if (session != null) {
0198: // If we have a session for this user, simply reuse
0199: if (userId != null
0200: && userId.equals(session.getUserId())) {
0201: return session;
0202: }
0203:
0204: // if it is for another user, we will create a new session, log a warning, and unbound/close the existing one
0205: s.setAttribute(USAGE_SESSION_KEY, null);
0206: M_log
0207: .warn("startSession: replacing existing UsageSession: "
0208: + session.getId()
0209: + " user: "
0210: + session.getUserId()
0211: + " for new user: " + userId);
0212: }
0213:
0214: // create the usage session and bind it to the session
0215: session = new BaseUsageSession(idManager().createUuid(),
0216: serverConfigurationService().getServerIdInstance(),
0217: userId, remoteAddress, userAgent, null, null);
0218:
0219: // store
0220: if (m_storage.addSession(session)) {
0221: // set as the current session
0222: s.setAttribute(USAGE_SESSION_KEY, session);
0223:
0224: return session;
0225: }
0226: }
0227:
0228: return null;
0229: }
0230:
0231: /**
0232: * {@inheritDoc}
0233: */
0234: public UsageSession getSession() {
0235: UsageSession rv = null;
0236:
0237: // do we have a current session?
0238: Session s = sessionManager().getCurrentSession();
0239: if (s != null) {
0240: // do we have a usage session in the session?
0241: rv = (BaseUsageSession) s.getAttribute(USAGE_SESSION_KEY);
0242: }
0243:
0244: else {
0245: M_log
0246: .warn("getSession: no current SessionManager session!");
0247: }
0248:
0249: return rv;
0250: }
0251:
0252: /**
0253: * @inheritDoc
0254: */
0255: public String getSessionId() {
0256: String rv = null;
0257:
0258: // See http://bugs.sakaiproject.org/jira/browse/SAK-1507
0259: // At server startup, when Spring is initializing components, there may not
0260: // be a session manager yet. This adaptor may be called before all components
0261: // are initialized since there are hidden dependencies (through static covers)
0262: // of which Spring is not aware. Therefore, check for and handle a null
0263: // sessionManager().
0264: if (sessionManager() == null)
0265: return null;
0266:
0267: // do we have a current session?
0268: Session s = sessionManager().getCurrentSession();
0269: if (s != null) {
0270: // do we have a usage session in the session?
0271: BaseUsageSession session = (BaseUsageSession) s
0272: .getAttribute(USAGE_SESSION_KEY);
0273: if (session != null) {
0274: rv = session.getId();
0275: }
0276: }
0277:
0278: // may be null, which indicates that there's no session
0279: return rv;
0280: }
0281:
0282: /**
0283: * @inheritDoc
0284: */
0285: public SessionState getSessionState(String key) {
0286: // map this to the sakai session's tool session concept, using key as the placement id
0287: Session s = sessionManager().getCurrentSession();
0288: if (s != null) {
0289: return new SessionStateWrapper(s.getToolSession(key));
0290: }
0291:
0292: M_log.warn("getSessionState(): no session: key: " + key);
0293: return null;
0294: }
0295:
0296: /**
0297: * @inheritDoc
0298: */
0299: public UsageSession setSessionActive(boolean auto) {
0300: throw new UnsupportedOperationException();
0301: // BaseUsageSession session = (BaseUsageSession) getSession();
0302: // if (session == null) return null;
0303: //
0304: // if (session.isClosed()) return session;
0305: //
0306: // if (auto)
0307: // {
0308: // // do not mark the current session as having user activity
0309: // // but close it if it's timed out from no user activity
0310: // if (session.isInactive())
0311: // {
0312: // session.close();
0313: // }
0314: // }
0315: // else
0316: // {
0317: // // mark the current session as having user activity
0318: // session.setActivity();
0319: // }
0320: //
0321: // return session;
0322: }
0323:
0324: /**
0325: * @inheritDoc
0326: */
0327: public UsageSession getSession(String id) {
0328: UsageSession rv = m_storage.getSession(id);
0329:
0330: return rv;
0331: }
0332:
0333: /**
0334: * @inheritDoc
0335: */
0336: public List getSessions(List ids) {
0337: List rv = m_storage.getSessions(ids);
0338:
0339: return rv;
0340: }
0341:
0342: /**
0343: * @inheritDoc
0344: */
0345: public List getSessions(String joinTable, String joinAlias,
0346: String joinColumn, String joinCriteria, Object[] values) {
0347: List rv = m_storage.getSessions(joinTable, joinAlias,
0348: joinColumn, joinCriteria, values);
0349:
0350: return rv;
0351: }
0352:
0353: /**
0354: * @inheritDoc
0355: */
0356: public int getSessionInactiveTimeout() {
0357: throw new UnsupportedOperationException();
0358: }
0359:
0360: /**
0361: * @inheritDoc
0362: */
0363: public int getSessionLostTimeout() {
0364: throw new UnsupportedOperationException();
0365: }
0366:
0367: /**
0368: * @inheritDoc
0369: */
0370: public List getOpenSessions() {
0371: return m_storage.getOpenSessions();
0372: }
0373:
0374: /**
0375: * @inheritDoc
0376: */
0377: public Map getOpenSessionsByServer() {
0378: List all = m_storage.getOpenSessions();
0379:
0380: Map byServer = new TreeMap();
0381:
0382: List current = null;
0383: String key = null;
0384:
0385: for (Iterator i = all.iterator(); i.hasNext();) {
0386: UsageSession s = (UsageSession) i.next();
0387:
0388: // to start, or when the server changes, create a new inner list and add to the map
0389: if ((key == null) || (!key.equals(s.getServer()))) {
0390: key = s.getServer();
0391: current = new Vector();
0392: byServer.put(key, current);
0393: }
0394:
0395: current.add(s);
0396: }
0397:
0398: return byServer;
0399: }
0400:
0401: /**
0402: * @inheritDoc
0403: */
0404: public boolean login(Authentication authn, HttpServletRequest req) {
0405: // establish the user's session - this has been known to fail
0406: UsageSession session = startSession(authn.getUid(), req
0407: .getRemoteAddr(), req.getHeader("user-agent"));
0408: if (session == null) {
0409: return false;
0410: }
0411:
0412: // set the user information into the current session
0413: Session sakaiSession = sessionManager().getCurrentSession();
0414: sakaiSession.setUserId(authn.getUid());
0415: sakaiSession.setUserEid(authn.getEid());
0416:
0417: // update the user's externally provided realm definitions
0418: authzGroupService().refreshUser(authn.getUid());
0419:
0420: // post the login event
0421: eventTrackingService().post(
0422: eventTrackingService()
0423: .newEvent(EVENT_LOGIN, null, true));
0424:
0425: return true;
0426: }
0427:
0428: /**
0429: * @inheritDoc
0430: */
0431: public void logout() {
0432: userDirectoryService().destroyAuthentication();
0433:
0434: // invalidate the sakai session, which makes it unavailable, unbinds all the bound objects,
0435: // including the session, which will close and generate the logout event
0436: Session sakaiSession = sessionManager().getCurrentSession();
0437: sakaiSession.invalidate();
0438: }
0439:
0440: /**
0441: * Generate the logout event.
0442: */
0443: protected void logoutEvent(UsageSession session) {
0444: if (session == null) {
0445: // generate a logout event (current session)
0446: eventTrackingService().post(
0447: eventTrackingService().newEvent(EVENT_LOGOUT, null,
0448: true));
0449: } else {
0450: // generate a logout event (this session)
0451: eventTrackingService().post(
0452: eventTrackingService().newEvent(EVENT_LOGOUT, null,
0453: true), session);
0454: }
0455: }
0456:
0457: /**********************************************************************************************************************************************************************************************************************************************************
0458: * Storage
0459: *********************************************************************************************************************************************************************************************************************************************************/
0460:
0461: protected interface Storage {
0462: /**
0463: * Open.
0464: */
0465: void open();
0466:
0467: /**
0468: * Close.
0469: */
0470: void close();
0471:
0472: /**
0473: * Take this session into storage.
0474: *
0475: * @param session
0476: * The usage session.
0477: * @return true if added successfully, false if not.
0478: */
0479: boolean addSession(UsageSession session);
0480:
0481: /**
0482: * Access a session by id
0483: *
0484: * @param id
0485: * The session id.
0486: * @return The session object.
0487: */
0488: UsageSession getSession(String id);
0489:
0490: /**
0491: * Access a bunch of sessions by the List id session ids.
0492: *
0493: * @param ids
0494: * The session id List.
0495: * @return The List (UsageSession) of session objects for these ids.
0496: */
0497: List getSessions(List ids);
0498:
0499: /**
0500: * Access a List of usage sessions by *arbitrary criteria* for te session ids.
0501: *
0502: * @param joinTable
0503: * the table name to (inner) join to
0504: * @param joinAlias
0505: * the alias used in the criteria string for the joinTable
0506: * @param joinColumn
0507: * the column name of the joinTable that is to match the session id in the join ON clause
0508: * @param joinCriteria
0509: * the criteria of the select (after the where)
0510: * @param fields
0511: * Optional values to go with the criteria in an implementation specific way.
0512: * @return The List (UsageSession) of UsageSession object for these ids.
0513: */
0514: List getSessions(String joinTable, String joinAlias,
0515: String joinColumn, String joinCriteria, Object[] values);
0516:
0517: /**
0518: * This session is now closed.
0519: *
0520: * @param session
0521: * The session which is closed.
0522: */
0523: void closeSession(UsageSession session);
0524:
0525: /**
0526: * Access a list of all open sessions.
0527: *
0528: * @return a List (UsageSession) of all open sessions, ordered by server, then by start (asc)
0529: */
0530: List getOpenSessions();
0531: }
0532:
0533: /**********************************************************************************************************************************************************************************************************************************************************
0534: * UsageSession
0535: *********************************************************************************************************************************************************************************************************************************************************/
0536:
0537: protected class BaseUsageSession implements UsageSession,
0538: SessionBindingListener {
0539: /** The user id for this session. */
0540: protected String m_user = null;
0541:
0542: /** The unique id for this session. */
0543: protected String m_id = null;
0544:
0545: /** The server which is hosting the session. */
0546: protected String m_server = null;
0547:
0548: /** The IP Address from which this session originated. */
0549: protected String m_ip = null;
0550:
0551: /** The User Agent string describing the browser used in this session. */
0552: protected String m_userAgent = null;
0553:
0554: /** The BrowserID string describing the browser used in this session. */
0555: protected String m_browserId = null;
0556:
0557: /** The time the session was started */
0558: protected Time m_start = null;
0559:
0560: /** The time the session was closed. */
0561: protected Time m_end = null;
0562:
0563: /**
0564: * Construct fully.
0565: *
0566: * @param id
0567: * The session id.
0568: * @param server
0569: * The server id which is hosting the session.
0570: * @param user
0571: * The user id for this session.
0572: * @param address
0573: * The IP Address from which this session originated.
0574: * @param agent
0575: * The User Agent string describing the browser used in this session.
0576: */
0577: public BaseUsageSession(String id, String server, String user,
0578: String address, String agent, Time start, Time end) {
0579: m_id = id;
0580: m_server = server;
0581: m_user = user;
0582: m_ip = address;
0583: m_userAgent = agent;
0584: if (start != null) {
0585: m_start = start;
0586: m_end = end;
0587: } else {
0588: m_start = timeService().newTime();
0589: m_end = m_start;
0590: }
0591: setBrowserId(agent);
0592: }
0593:
0594: /**
0595: * Set the browser id for this session, decoded from the user agent string.
0596: *
0597: * @param agent
0598: * The user agent string.
0599: */
0600: protected void setBrowserId(String agent) {
0601: if (agent == null) {
0602: m_browserId = UNKNOWN;
0603: }
0604:
0605: // test whether agent is UserAgent value for a known browser.
0606: // should we also check version number?
0607: else if (agent.indexOf("Netscape") >= 0
0608: && agent.indexOf("Mac") >= 0) {
0609: m_browserId = MAC_NN;
0610: } else if (agent.indexOf("Netscape") >= 0
0611: && agent.indexOf("Windows") >= 0) {
0612: m_browserId = WIN_NN;
0613: } else if (agent.indexOf("MSIE") >= 0
0614: && agent.indexOf("Mac") >= 0) {
0615: m_browserId = MAC_IE;
0616: } else if (agent.indexOf("MSIE") >= 0
0617: && agent.indexOf("Windows") >= 0) {
0618: m_browserId = WIN_IE;
0619: } else if (agent.indexOf("Camino") >= 0
0620: && agent.indexOf("Macintosh") >= 0) {
0621: m_browserId = MAC_CM;
0622: } else if (agent.startsWith("Mozilla")
0623: && agent.indexOf("Windows") >= 0) {
0624: m_browserId = WIN_MZ;
0625: } else if (agent.startsWith("Mozilla")
0626: && agent.indexOf("Macintosh") >= 0) {
0627: m_browserId = MAC_MZ;
0628: } else {
0629: m_browserId = UNKNOWN;
0630: }
0631: }
0632:
0633: /**
0634: * Close the session.
0635: */
0636: protected void close() {
0637: if (!isClosed()) {
0638: m_end = timeService().newTime();
0639: m_storage.closeSession(this );
0640: }
0641: }
0642:
0643: /**
0644: * @inheritDoc
0645: */
0646: public boolean isClosed() {
0647: return (!(m_end.equals(m_start)));
0648: }
0649:
0650: /**
0651: * @inheritDoc
0652: */
0653: public String getUserId() {
0654: return m_user;
0655: }
0656:
0657: /**
0658: * @inheritDoc
0659: */
0660: public String getUserEid() {
0661: try {
0662: return userDirectoryService().getUserEid(m_user);
0663: } catch (UserNotDefinedException e) {
0664: return m_user;
0665: }
0666: }
0667:
0668: /**
0669: * @inheritDoc
0670: */
0671: public String getUserDisplayId() {
0672: try {
0673: User user = userDirectoryService().getUser(m_user);
0674: return user.getDisplayId();
0675: } catch (UserNotDefinedException e) {
0676: return m_user;
0677: }
0678: }
0679:
0680: /**
0681: * @inheritDoc
0682: */
0683: public String getId() {
0684: return m_id;
0685: }
0686:
0687: /**
0688: * @inheritDoc
0689: */
0690: public String getServer() {
0691: return m_server;
0692: }
0693:
0694: /**
0695: * @inheritDoc
0696: */
0697: public String getIpAddress() {
0698: return m_ip;
0699: }
0700:
0701: /**
0702: * @inheritDoc
0703: */
0704: public String getUserAgent() {
0705: return m_userAgent;
0706: }
0707:
0708: /**
0709: * @inheritDoc
0710: */
0711: public String getBrowserId() {
0712: return m_browserId;
0713: }
0714:
0715: /**
0716: * @inheritDoc
0717: */
0718: public Time getStart() {
0719: return timeService().newTime(m_start.getTime());
0720: }
0721:
0722: /**
0723: * @inheritDoc
0724: */
0725: public Time getEnd() {
0726: return timeService().newTime(m_end.getTime());
0727: }
0728:
0729: /**
0730: * There's new user activity now.
0731: */
0732: protected void setActivity() {
0733: throw new UnsupportedOperationException();
0734: }
0735:
0736: /**
0737: * Has this session gone inactive?
0738: *
0739: * @return True if the session has seen no activity in the last timeout period, false if it's still active.
0740: */
0741: protected boolean isInactive() {
0742: throw new UnsupportedOperationException();
0743: }
0744:
0745: /**
0746: * @inheritDoc
0747: */
0748: public void valueBound(SessionBindingEvent sbe) {
0749: }
0750:
0751: /**
0752: * @inheritDoc
0753: */
0754: public void valueUnbound(SessionBindingEvent sbe) {
0755: // if we didn't close this already, close
0756: if (!isClosed()) {
0757: // close the session
0758: close();
0759:
0760: // generate the logout event
0761: logoutEvent(this );
0762: }
0763: }
0764:
0765: /**
0766: * @inheritDoc
0767: */
0768: public int compareTo(Object obj) {
0769: if (!(obj instanceof UsageSession))
0770: throw new ClassCastException();
0771:
0772: // if the object are the same, say so
0773: if (obj == this )
0774: return 0;
0775:
0776: // start the compare by comparing their users
0777: int compare = getUserId().compareTo(
0778: ((UsageSession) obj).getUserId());
0779:
0780: // if these are the same
0781: if (compare == 0) {
0782: // sort based on (unique) id
0783: compare = getId().compareTo(
0784: ((UsageSession) obj).getId());
0785: }
0786:
0787: return compare;
0788: }
0789:
0790: /**
0791: * @inheritDoc
0792: */
0793: public String toString() {
0794: return "[" + ((m_id == null) ? "" : m_id) + " | "
0795: + ((m_server == null) ? "" : m_server) + " | "
0796: + ((m_user == null) ? "" : m_user) + " | "
0797: + ((m_ip == null) ? "" : m_ip) + " | "
0798: + ((m_userAgent == null) ? "" : m_userAgent)
0799: + " | " + m_start.toStringGmtFull() + " ]";
0800: }
0801: }
0802:
0803: /**********************************************************************************************************************************************************************************************************************************************************
0804: * SessionState
0805: *********************************************************************************************************************************************************************************************************************************************************/
0806:
0807: public class SessionStateWrapper implements SessionState {
0808: /** The ToolSession object wrapped. */
0809: protected ToolSession m_session = null;
0810:
0811: public SessionStateWrapper(ToolSession session) {
0812: m_session = session;
0813: }
0814:
0815: /**
0816: * @inheritDoc
0817: */
0818: public Object getAttribute(String name) {
0819: return m_session.getAttribute(name);
0820: }
0821:
0822: /**
0823: * @inheritDoc
0824: */
0825: public Object setAttribute(String name, Object value) {
0826: Object old = m_session.getAttribute(name);
0827: unBindAttributeValue(name, old);
0828:
0829: m_session.setAttribute(name, value);
0830: bindAttributeValue(name, value);
0831:
0832: return old;
0833: }
0834:
0835: /**
0836: * @inheritDoc
0837: */
0838: public Object removeAttribute(String name) {
0839: Object old = m_session.getAttribute(name);
0840: unBindAttributeValue(name, old);
0841:
0842: m_session.removeAttribute(name);
0843:
0844: return old;
0845: }
0846:
0847: /**
0848: * @inheritDoc
0849: */
0850: public void clear() {
0851: // unbind
0852: for (Enumeration e = m_session.getAttributeNames(); e
0853: .hasMoreElements();) {
0854: String name = (String) e.nextElement();
0855: Object value = m_session.getAttribute(name);
0856: unBindAttributeValue(name, value);
0857: }
0858:
0859: m_session.clearAttributes();
0860: }
0861:
0862: /**
0863: * @inheritDoc
0864: */
0865: public List getAttributeNames() {
0866: List rv = new Vector();
0867: for (Enumeration e = m_session.getAttributeNames(); e
0868: .hasMoreElements();) {
0869: String name = (String) e.nextElement();
0870: rv.add(name);
0871: }
0872:
0873: return rv;
0874: }
0875:
0876: /**
0877: * @inheritDoc
0878: */
0879: public int size() {
0880: throw new UnsupportedOperationException();
0881: }
0882:
0883: /**
0884: * @inheritDoc
0885: */
0886: public boolean isEmpty() {
0887: throw new UnsupportedOperationException();
0888: }
0889:
0890: /**
0891: * @inheritDoc
0892: */
0893: public boolean containsKey(Object key) {
0894: throw new UnsupportedOperationException();
0895: }
0896:
0897: /**
0898: * @inheritDoc
0899: */
0900: public boolean containsValue(Object value) {
0901: throw new UnsupportedOperationException();
0902: }
0903:
0904: /**
0905: * @inheritDoc
0906: */
0907: public Object get(Object key) {
0908: throw new UnsupportedOperationException();
0909: }
0910:
0911: /**
0912: * @inheritDoc
0913: */
0914: public Object put(Object key, Object value) {
0915: throw new UnsupportedOperationException();
0916: }
0917:
0918: /**
0919: * @inheritDoc
0920: */
0921: public Object remove(Object key) {
0922: throw new UnsupportedOperationException();
0923: }
0924:
0925: /**
0926: * @inheritDoc
0927: */
0928: public void putAll(Map t) {
0929: throw new UnsupportedOperationException();
0930: }
0931:
0932: /**
0933: * @inheritDoc
0934: */
0935: public Set keySet() {
0936: throw new UnsupportedOperationException();
0937: }
0938:
0939: /**
0940: * @inheritDoc
0941: */
0942: public Collection values() {
0943: throw new UnsupportedOperationException();
0944: }
0945:
0946: /**
0947: * @inheritDoc
0948: */
0949: public Set entrySet() {
0950: throw new UnsupportedOperationException();
0951: }
0952:
0953: /**
0954: * If the object is a SessionStateBindingListener, unbind it
0955: *
0956: * @param attributeName
0957: * The attribute name.
0958: * @param attribute
0959: * The attribute object
0960: */
0961: protected void unBindAttributeValue(String attributeName,
0962: Object attribute) {
0963: // if this object wants session binding notification
0964: if ((attribute != null)
0965: && (attribute instanceof SessionStateBindingListener)) {
0966: try {
0967: ((SessionStateBindingListener) attribute)
0968: .valueUnbound(null, attributeName);
0969: } catch (Throwable e) {
0970: M_log
0971: .warn(
0972: "unBindAttributeValue: unbinding exception: ",
0973: e);
0974: }
0975: }
0976: }
0977:
0978: /**
0979: * If the object is a SessionStateBindingListener, bind it
0980: *
0981: * @param attributeName
0982: * The attribute name.
0983: * @param attribute
0984: * The attribute object
0985: */
0986: protected void bindAttributeValue(String attributeName,
0987: Object attribute) {
0988: // if this object wants session binding notification
0989: if ((attribute != null)
0990: && (attribute instanceof SessionStateBindingListener)) {
0991: try {
0992: ((SessionStateBindingListener) attribute)
0993: .valueBound(null, attributeName);
0994: } catch (Throwable e) {
0995: M_log
0996: .warn(
0997: "bindAttributeValue: unbinding exception: ",
0998: e);
0999: }
1000: }
1001: }
1002: }
1003:
1004: /**********************************************************************************************************************************************************************************************************************************************************
1005: * Storage component
1006: *********************************************************************************************************************************************************************************************************************************************************/
1007:
1008: protected class ClusterStorage implements Storage {
1009: /**
1010: * Open and be ready to read / write.
1011: */
1012: public void open() {
1013: // if we are auto-creating our schema, check and create
1014: if (m_autoDdl) {
1015: sqlService().ddl(this .getClass().getClassLoader(),
1016: "sakai_session");
1017: }
1018: }
1019:
1020: /**
1021: * Close.
1022: */
1023: public void close() {
1024: }
1025:
1026: /**
1027: * Take this session into storage.
1028: *
1029: * @param session
1030: * The usage session.
1031: * @return true if added successfully, false if not.
1032: */
1033: public boolean addSession(UsageSession session) {
1034: // and store it in the db
1035: String statement = "insert into SAKAI_SESSION (SESSION_ID,SESSION_SERVER,SESSION_USER,SESSION_IP,SESSION_USER_AGENT,SESSION_START,SESSION_END) values (?, ?, ?, ?, ?, ?, ?)";
1036:
1037: // collect the fields
1038: Object fields[] = new Object[7];
1039: fields[0] = session.getId();
1040: fields[1] = session.getServer();
1041: fields[2] = session.getUserId();
1042: fields[3] = session.getIpAddress();
1043: fields[4] = session.getUserAgent();
1044: fields[5] = session.getStart();
1045: fields[6] = session.getEnd();
1046:
1047: // process the insert
1048: boolean ok = sqlService().dbWrite(statement, fields);
1049: if (!ok) {
1050: M_log.warn(".addSession(): dbWrite failed");
1051: return false;
1052: }
1053:
1054: return true;
1055:
1056: } // addSession
1057:
1058: /**
1059: * Access a session by id
1060: *
1061: * @param id
1062: * The session id.
1063: * @return The session object.
1064: */
1065: public UsageSession getSession(String id) {
1066: UsageSession rv = null;
1067:
1068: // check the db
1069: String statement = "select SESSION_ID,SESSION_SERVER,SESSION_USER,SESSION_IP,SESSION_USER_AGENT,SESSION_START,SESSION_END from SAKAI_SESSION where SESSION_ID = ?";
1070:
1071: // send in the last seq number parameter
1072: Object[] fields = new Object[1];
1073: fields[0] = id;
1074:
1075: List sessions = sqlService().dbRead(statement, fields,
1076: new SqlReader() {
1077: public Object readSqlResultRecord(
1078: ResultSet result) {
1079: try {
1080: // read the UsageSession
1081: String id = result.getString(1);
1082: String server = result.getString(2);
1083: String userId = result.getString(3);
1084: String ip = result.getString(4);
1085: String agent = result.getString(5);
1086: Time start = timeService().newTime(
1087: result.getTimestamp(6,
1088: sqlService().getCal())
1089: .getTime());
1090: Time end = timeService().newTime(
1091: result.getTimestamp(7,
1092: sqlService().getCal())
1093: .getTime());
1094:
1095: UsageSession session = new BaseUsageSession(
1096: id, server, userId, ip, agent,
1097: start, end);
1098: return session;
1099: } catch (SQLException ignore) {
1100: return null;
1101: }
1102: }
1103: });
1104:
1105: if (!sessions.isEmpty())
1106: rv = (UsageSession) sessions.get(0);
1107:
1108: return rv;
1109:
1110: } // getSession
1111:
1112: /**
1113: * @inheritDoc
1114: */
1115: public List getSessions(List ids) {
1116: // TODO: do this in a single SQL call! -ggolden
1117: List rv = new Vector();
1118: for (Iterator i = ids.iterator(); i.hasNext();) {
1119: String id = (String) i.next();
1120: UsageSession s = getSession(id);
1121: if (s != null) {
1122: rv.add(s);
1123: }
1124: }
1125:
1126: return rv;
1127: }
1128:
1129: /**
1130: * Access a List of usage sessions by *arbitrary criteria* for te session ids.
1131: *
1132: * @param joinTable
1133: * the table name to (inner) join to
1134: * @param joinAlias
1135: * the alias used in the criteria string for the joinTable
1136: * @param joinColumn
1137: * the column name of the joinTable that is to match the session id in the join ON clause
1138: * @param joinCriteria
1139: * the criteria of the select (after the where)
1140: * @param fields
1141: * Optional values to go with the criteria in an implementation specific way.
1142: * @return The List (UsageSession) of UsageSession object for these ids.
1143: */
1144: public List getSessions(String joinTable, String joinAlias,
1145: String joinColumn, String joinCriteria, Object[] values) {
1146: UsageSession rv = null;
1147:
1148: // use an alias different from the alias given
1149: String alias = joinAlias + "X";
1150:
1151: // use criteria as the where clause
1152: String statement = "select " + alias + ".SESSION_ID,"
1153: + alias + ".SESSION_SERVER," + alias
1154: + ".SESSION_USER," + alias + ".SESSION_IP," + alias
1155: + ".SESSION_USER_AGENT," + alias
1156: + ".SESSION_START," + alias + ".SESSION_END"
1157: + " from SAKAI_SESSION " + alias + " inner join "
1158: + joinTable + " " + joinAlias + " ON " + alias
1159: + ".SESSION_ID = " + joinAlias + "." + joinColumn
1160: + " where " + joinCriteria;
1161:
1162: List sessions = sqlService().dbRead(statement, values,
1163: new SqlReader() {
1164: public Object readSqlResultRecord(
1165: ResultSet result) {
1166: try {
1167: // read the UsageSession
1168: String id = result.getString(1);
1169: String server = result.getString(2);
1170: String userId = result.getString(3);
1171: String ip = result.getString(4);
1172: String agent = result.getString(5);
1173: Time start = timeService().newTime(
1174: result.getTimestamp(6,
1175: sqlService().getCal())
1176: .getTime());
1177: Time end = timeService().newTime(
1178: result.getTimestamp(7,
1179: sqlService().getCal())
1180: .getTime());
1181:
1182: UsageSession session = new BaseUsageSession(
1183: id, server, userId, ip, agent,
1184: start, end);
1185: return session;
1186: } catch (SQLException ignore) {
1187: return null;
1188: }
1189: }
1190: });
1191:
1192: return sessions;
1193: }
1194:
1195: /**
1196: * This session is now closed.
1197: *
1198: * @param session
1199: * The session which is closed.
1200: */
1201: public void closeSession(UsageSession session) {
1202: // close the session on the db
1203: String statement = "update SAKAI_SESSION set SESSION_END = ? where SESSION_ID = ?";
1204:
1205: // collect the fields
1206: Object fields[] = new Object[2];
1207: fields[0] = session.getEnd();
1208: fields[1] = session.getId();
1209:
1210: // process the statement
1211: boolean ok = sqlService().dbWrite(statement, fields);
1212: if (!ok) {
1213: M_log.warn(".closeSession(): dbWrite failed");
1214: }
1215:
1216: } // closeSession
1217:
1218: /**
1219: * Access a list of all open sessions.
1220: *
1221: * @return a List (UsageSession) of all open sessions, ordered by server, then by start (asc)
1222: */
1223: public List getOpenSessions() {
1224: UsageSession rv = null;
1225:
1226: // check the db
1227: String statement = "select SESSION_ID,SESSION_SERVER,SESSION_USER,SESSION_IP,SESSION_USER_AGENT,SESSION_START,SESSION_END"
1228: + " from SAKAI_SESSION where SESSION_START = SESSION_END ORDER BY SESSION_SERVER ASC, SESSION_START ASC";
1229:
1230: List sessions = sqlService().dbRead(statement, null,
1231: new SqlReader() {
1232: public Object readSqlResultRecord(
1233: ResultSet result) {
1234: try {
1235: // read the UsageSession
1236: String id = result.getString(1);
1237: String server = result.getString(2);
1238: String userId = result.getString(3);
1239: String ip = result.getString(4);
1240: String agent = result.getString(5);
1241: Time start = timeService().newTime(
1242: result.getTimestamp(6,
1243: sqlService().getCal())
1244: .getTime());
1245: Time end = timeService().newTime(
1246: result.getTimestamp(7,
1247: sqlService().getCal())
1248: .getTime());
1249:
1250: UsageSession session = new BaseUsageSession(
1251: id, server, userId, ip, agent,
1252: start, end);
1253: return session;
1254: } catch (SQLException ignore) {
1255: return null;
1256: }
1257: }
1258: });
1259:
1260: return sessions;
1261: }
1262: }
1263: }
|