Index: lams_common/src/java/org/lamsfoundation/lams/commonContext.xml
===================================================================
diff -u -ra99d5750b6665025226cb1a4854cbc683debfaad -rebbe77ec5ad6506eca4b642562cf9898c0d7d587
--- lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision a99d5750b6665025226cb1a4854cbc683debfaad)
+++ lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision ebbe77ec5ad6506eca4b642562cf9898c0d7d587)
@@ -189,4 +189,13 @@
+
+
+ 60
+
+
Index: lams_common/src/java/org/lamsfoundation/lams/web/session/SessionManager.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/web/session/SessionManager.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/web/session/SessionManager.java (revision ebbe77ec5ad6506eca4b642562cf9898c0d7d587)
@@ -0,0 +1,395 @@
+/*
+ *Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ *
+ *This program is free software; you can redistribute it and/or modify
+ *it under the terms of the GNU General Public License as published by
+ *the Free Software Foundation; either version 2 of the License, or
+ *(at your option) any later version.
+ *
+ *This program is distributed in the hope that it will be useful,
+ *but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *GNU General Public License for more details.
+ *
+ *You should have received a copy of the GNU General Public License
+ *along with this program; if not, write to the Free Software
+ *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *USA
+ *
+ *http://www.gnu.org/licenses/gpl.txt
+ */
+package org.lamsfoundation.lams.web.session;
+
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionContext;
+
+import org.apache.log4j.Logger;
+import org.lamsfoundation.lams.util.Configuration;
+import org.lamsfoundation.lams.util.ConfigurationKeys;
+
+import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
+/**
+ *
+ * @author Steve.Ni
+ *
+ * $version$
+ */
+public class SessionManager{
+
+ private static final Logger log = Logger.getLogger(SessionManager.class);
+
+ //signlton
+ private static SessionManager sessionMgr;
+
+ public static final String SYS_SESSION_NAME = "sys_session";
+
+ //KEY: sessionId, each session will have an identified id. VALUE: SessionImpl instance, which contains
+ //true session key/value pairs.
+ private Map sessionContainer = new ConcurrentReaderHashMap();
+ //Save current session id
+ private ThreadLocal currentSessionIdContainer = new ThreadLocal();
+
+ //The system monitoring thread instance
+ private Monitor monitor;
+ //The sleep time in seconds period to monitoring the thread.
+ //This attribute could be set in spring context.xml.
+ private short monitorPeriod = 20;
+
+ /**
+ * Get the singleton instance of this class.
+ * @return
+ */
+ private static SessionManager getInstance(){
+ if(sessionMgr == null)
+ log.error("init SessionManager failed");
+
+ return sessionMgr;
+ }
+ /**
+ * Get system level HttpSession by current session id.
+ * @return HttpSession instanceof org.lamsfoundation.lams.systemsession.SessionManager#SessionImpl
+ */
+ public static HttpSession getSession(){
+ String sessionId = (String) getInstance().currentSessionIdContainer.get();
+ return getSession(sessionId);
+ }
+ /**
+ * Get system session by given session id.
+ * @param sessionId
+ * @return system session. Return an null if the given sessionid can not map to an existed session.
+ */
+ public static HttpSession getSession(String sessionId){
+ if(sessionId == null){
+ log.error("Failed on finding current system session with null sessionId");
+ return null;
+ }
+ return (HttpSession) getInstance().sessionContainer.get(sessionId);
+
+ }
+
+ static void createSession(String sessionId){
+ //initialize a new one
+ HttpSession session = getInstance().new SessionImpl(sessionId);
+ getInstance().sessionContainer.put(sessionId,session);
+ }
+
+ /**
+ * Return SessionVisitor
of currentSessionId
.
+ * An internal method, only avaliable in package.
+ * @return
+ */
+ static SessionVisitor getSessionVisitor() {
+ return (SessionVisitor)getSession();
+ }
+ /**
+ * An internal method, only avaliable in package.
+ * @param currentSessionId
+ */
+ static void setCurrentSessionId(String currentSessionId) {
+ getInstance().currentSessionIdContainer.set(currentSessionId);
+ }
+ /**
+ * This class initialize method called by Spring framework.
+ */
+ public void init(){
+ if(sessionMgr == null){
+ //only start once
+ sessionMgr = this;
+ if (monitorPeriod > 0){
+ monitor = new Monitor();
+ monitor.start();
+ }
+ }
+ }
+ /**
+ * This class destroy method called by Spring framework.
+ */
+ public void destroy(){
+ if(monitor != null){
+ sessionMgr = null;
+ monitor.stop();
+ monitor = null;
+ }
+
+ }
+
+ public short getMonitorPeriod() {
+ return monitorPeriod;
+ }
+ public void setMonitorPeriod(short monitorPeriod) {
+ this.monitorPeriod = monitorPeriod;
+ }
+
+ //************************************************************************
+ // SYSTEM SESSION MONITOR CLASS
+ //************************************************************************
+ class Monitor implements Runnable{
+ private static final String THREAD_NAME = "LAMS SYSTEM SESSION MONITOR";
+ private Thread monitoringThread;
+ private boolean stopSign = false;
+ public void start(){
+ monitoringThread = new Thread(this,THREAD_NAME);
+ stopSign = false;
+ monitoringThread.start();
+ }
+ public void run() {
+ while (!stopSign) {
+ try {
+ //check whether session is expired
+ Iterator iter = sessionContainer.values().iterator();
+ while(iter.hasNext()) {
+ SessionImpl session = (SessionImpl) iter.next();
+ if(session.getMaxInactiveInterval() > 0){
+ if ((System.currentTimeMillis() - session.getLastAccessedTime() -
+ session.getMaxInactiveInterval() * 1000L) > 0)
+ session.invalidate();
+ }
+ }
+ } catch (Throwable e) {
+ log.warn("Monitor thread exception: " + e);
+ }
+ if (!stopSign) {
+ try {
+ Thread.sleep(monitorPeriod * 1000L);
+ } catch (Exception e) {
+ // do nothing
+ }
+ }
+ }
+ }
+
+ public void stop(){
+
+ if (monitoringThread != null){
+ stopSign = true;
+ monitoringThread.interrupt();
+ try{
+ monitoringThread.join();
+ }catch (InterruptedException ignore){
+ log.error("Exception when interruptting Session Monitoring Thread");
+ }
+ monitoringThread = null;
+ }
+ }
+ }
+ //************************************************************************
+ // SYSTEM SESSION IMPLEMENTAION CLASS
+ //************************************************************************
+ class SessionImpl implements HttpSession,SessionVisitor {
+
+ private String sessionId;
+ private long createTime;
+ private long accessTime;
+ private int timeout;
+
+ private Map valueMap;
+
+ public SessionImpl(String sessionId){
+ this.sessionId = sessionId;
+ createTime = System.currentTimeMillis();
+ accessTime = createTime;
+ timeout = Configuration.getAsInt(ConfigurationKeys.INACTIVE_TIME);
+ valueMap = new ConcurrentReaderHashMap();
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public long getCreationTime() {
+ return createTime;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public String getId() {
+ return sessionId;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public long getLastAccessedTime() {
+ return accessTime;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public void setMaxInactiveInterval(int timeout) {
+ this.timeout = timeout;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public int getMaxInactiveInterval() {
+ return timeout;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getAttribute(String name) {
+ return valueMap.get(name);
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public Enumeration getAttributeNames() {
+
+ return new Enumeration(){
+ Iterator iter = valueMap.keySet().iterator();
+ public boolean hasMoreElements() {
+ return iter.hasNext();
+ }
+
+ public Object nextElement() {
+ return iter.next();
+ }
+
+ };
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public void setAttribute(String name, Object value) {
+ if(value == null)
+ removeAttribute(name);
+
+ Object old = valueMap.put(name, value);
+
+ fireBound(name, value);
+
+ if (old != null){
+ fireUnbound(name, old);
+ }
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public void removeAttribute(String name) {
+ Object value = valueMap.remove(name);
+ if(value != null)
+ fireUnbound(name, value);
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public void invalidate() {
+
+ Iterator iter = valueMap.entrySet().iterator();
+ while(iter.hasNext()){
+ Map.Entry entry = (Map.Entry) iter.next();
+ fireUnbound((String) entry.getKey(),entry.getValue());
+ }
+ valueMap.clear();
+ }
+ /**
+ * Notice: This method always return false
+ * {@inheritDoc}
+ */
+ public boolean isNew() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void putValue(String name, Object value) {
+ setAttribute(name,value);
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public void removeValue(String name) {
+ removeAttribute(name);
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public Object getValue(String name) {
+ return getAttribute(name);
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public String[] getValueNames() {
+ return (String[])valueMap.keySet().toArray(new String[valueMap.size()]);
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public HttpSessionContext getSessionContext() {
+ return new HttpSessionContext(){
+
+ public HttpSession getSession(String sessionId) {
+ return SessionImpl.this;
+ }
+
+ public Enumeration getIds() {
+ return new Enumeration(){
+ public boolean hasMoreElements() {
+ return false;
+ }
+ public Object nextElement() {
+ return null;
+ }
+ };
+ }
+
+ };
+ }
+ /**
+ * Notice: This method always return null.
+ * {@inheritDoc}
+ */
+ public ServletContext getServletContext() {
+ return null;
+ }
+ //**********************************************************
+ // SessionVisitor method
+ public void accessed() {
+ accessTime = System.currentTimeMillis();
+ }
+ //**********************************************************
+ // private method
+ private void fireUnbound(String name, Object value) {
+ if(value instanceof HttpSessionBindingListener){
+ HttpSessionBindingEvent event = new HttpSessionBindingEvent(this,name,value);
+ ((HttpSessionBindingListener)value).valueUnbound(event);
+ }
+ }
+ private void fireBound(String name, Object value) {
+ if(value instanceof HttpSessionBindingListener){
+ HttpSessionBindingEvent event = new HttpSessionBindingEvent(this,name,value);
+ ((HttpSessionBindingListener)value).valueBound(event);
+ }
+ }
+
+ }
+
+}
Index: lams_common/src/java/org/lamsfoundation/lams/web/session/SessionVisitor.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/web/session/SessionVisitor.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/web/session/SessionVisitor.java (revision ebbe77ec5ad6506eca4b642562cf9898c0d7d587)
@@ -0,0 +1,34 @@
+/*
+ *Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ *
+ *This program is free software; you can redistribute it and/or modify
+ *it under the terms of the GNU General Public License as published by
+ *the Free Software Foundation; either version 2 of the License, or
+ *(at your option) any later version.
+ *
+ *This program is distributed in the hope that it will be useful,
+ *but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *GNU General Public License for more details.
+ *
+ *You should have received a copy of the GNU General Public License
+ *along with this program; if not, write to the Free Software
+ *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *USA
+ *
+ *http://www.gnu.org/licenses/gpl.txt
+ */
+package org.lamsfoundation.lams.web.session;
+/**
+ * Provide some internal method to access session private values.
+ *
+ * @author Steve.Ni
+ * $version$
+ */
+interface SessionVisitor {
+ /**
+ * This method will reset session last access time
.
+ * Currently(23/09/2005), this method is only used in SystemSessionFilter
.
+ */
+ public void accessed();
+}
Index: lams_common/src/java/org/lamsfoundation/lams/web/session/SystemSessionFilter.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/web/session/SystemSessionFilter.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/web/session/SystemSessionFilter.java (revision ebbe77ec5ad6506eca4b642562cf9898c0d7d587)
@@ -0,0 +1,145 @@
+/*
+ *Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ *
+ *This program is free software; you can redistribute it and/or modify
+ *it under the terms of the GNU General Public License as published by
+ *the Free Software Foundation; either version 2 of the License, or
+ *(at your option) any later version.
+ *
+ *This program is distributed in the hope that it will be useful,
+ *but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *GNU General Public License for more details.
+ *
+ *You should have received a copy of the GNU General Public License
+ *along with this program; if not, write to the Free Software
+ *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ *USA
+ *
+ *http://www.gnu.org/licenses/gpl.txt
+ */
+package org.lamsfoundation.lams.web.session;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.sf.hibernate.id.UUIDHexGenerator;
+
+/**
+ *
+ * @author Steve.Ni
+ *
+ * $version$
+ */
+public class SystemSessionFilter implements Filter {
+
+ /** The name of the cookie we use to keep sakai session. */
+ public static final String SYS_SESSION_COOKIE = "SYSSESSIONID";
+
+ public void init(FilterConfig config) throws ServletException {
+ }
+
+ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+ throws IOException, ServletException {
+
+ // Skip non-http request/response
+ if (!((req instanceof HttpServletRequest) && (res instanceof HttpServletResponse))){
+ chain.doFilter(req, res);
+ return;
+ }
+
+ Cookie cookie = findCookie((HttpServletRequest) req,SYS_SESSION_COOKIE);
+ String currentSessionId = null;
+ if(cookie != null){
+ currentSessionId = cookie.getValue();
+ Object obj = SessionManager.getSession(currentSessionId);
+ //if cookie exist, but session does not. This usually menas seesion expired.
+ //then delete the cookie first and set it null in order to create a new one
+ if(obj == null){
+ removeCookie((HttpServletResponse) res,SYS_SESSION_COOKIE);
+ cookie = null;
+ }
+ }
+ //can not be in else!
+ if(cookie == null){
+ //create new session and set it into cookie
+ currentSessionId = (String) new UUIDHexGenerator().generate(null,null);
+ SessionManager.createSession(currentSessionId);
+ cookie = createCookie((HttpServletResponse) res,SYS_SESSION_COOKIE,currentSessionId);
+ }
+
+ SessionManager.setCurrentSessionId(currentSessionId);
+ //reset session last access time
+ SessionVisitor sessionVisitor = SessionManager.getSessionVisitor();
+ sessionVisitor.accessed();
+
+ //do following part of chain
+ chain.doFilter(req,res);
+
+ SessionManager.setCurrentSessionId(null);
+
+ }
+
+ public void destroy() {
+ //do nothing
+ }
+
+ /**
+ * Find a cookie by given cookie name from request.
+ *
+ * @param req
+ * @param name The cookie name
+ * @return The cookie of this name in the request, or null if not found.
+ */
+ private Cookie findCookie(HttpServletRequest req, String name)
+ {
+ Cookie[] cookies = req.getCookies();
+ if (cookies != null) {
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].getName().equals(name)) {
+ return cookies[i];
+ }
+ }
+ }
+
+ return null;
+ }
+ /**
+ * Remove cookie by given name from request
+ * @param res
+ * @param name
+ * @return the removed cookies
+ */
+ private Cookie removeCookie(HttpServletResponse res, String name){
+ Cookie cookie = new Cookie(name, "");
+ cookie.setPath("/");
+ cookie.setMaxAge(0);
+ res.addCookie(cookie);
+
+ return cookie;
+ }
+ /**
+ * Create a new cookie for request.
+ * @param res
+ * @param name cookie name
+ * @param value cookie value
+ * @return the created cookie.
+ */
+ private Cookie createCookie(HttpServletResponse res, String name, String value){
+ Cookie cookie = new Cookie(name, value);
+ cookie.setPath("/");
+ cookie.setMaxAge(-1);
+ res.addCookie(cookie);
+
+ return cookie;
+ }
+}