001: package com.icesoft.faces.webapp.http.servlet;
002:
003: import org.apache.commons.logging.Log;
004: import org.apache.commons.logging.LogFactory;
005:
006: import javax.servlet.ServletContextEvent;
007: import javax.servlet.ServletContextListener;
008: import javax.servlet.ServletException;
009: import javax.servlet.http.HttpServletRequest;
010: import javax.servlet.http.HttpServletResponse;
011: import javax.servlet.http.HttpSession;
012: import javax.servlet.http.HttpSessionEvent;
013: import javax.servlet.http.HttpSessionListener;
014: import java.util.ArrayList;
015: import java.util.HashMap;
016: import java.util.Iterator;
017: import java.util.List;
018: import java.util.Map;
019:
020: public abstract class SessionDispatcher implements PseudoServlet {
021: //having a static field here is ok because web applications are started in separate classloaders
022: private static final Log Log = LogFactory
023: .getLog(SessionDispatcher.class);
024: private final static List SessionDispatchers = new ArrayList();
025: private Map sessionBoundServers = new HashMap();
026:
027: protected SessionDispatcher() {
028: SessionDispatchers.add(this );
029: }
030:
031: public void service(HttpServletRequest request,
032: HttpServletResponse response) throws Exception {
033: HttpSession session = request.getSession(true);
034: //test if session is still around
035: if (sessionBoundServers.containsKey(session.getId())) {
036: PseudoServlet server = (PseudoServlet) sessionBoundServers
037: .get(session.getId());
038: server.service(request, response);
039: } else {
040: //session has expired in the mean time, server removed by the session listener
041: throw new ServletException("Session expired");
042: }
043: }
044:
045: public void shutdown() {
046: Iterator i = sessionBoundServers.values().iterator();
047: while (i.hasNext()) {
048: PseudoServlet server = (PseudoServlet) i.next();
049: server.shutdown();
050: }
051: }
052:
053: private void sessionCreated(HttpSession session) {
054: try {
055: sessionBoundServers.put(session.getId(), this .newServlet(
056: session, Listener.lookupSessionMonitor(session)));
057: } catch (Exception e) {
058: Log.warn(e);
059: throw new RuntimeException(e);
060: } catch (Throwable t) {
061: Log.warn(t);
062: throw new RuntimeException(t);
063: }
064: }
065:
066: private void sessionShutdown(HttpSession session) {
067: PseudoServlet server = (PseudoServlet) sessionBoundServers
068: .get(session.getId());
069: server.shutdown();
070: }
071:
072: private void sessionDestroyed(HttpSession session) {
073: sessionBoundServers.remove(session.getId());
074: }
075:
076: //Exposing MainSessionBoundServlet for Tomcat 6 Ajax Push
077: public static PseudoServlet getSingletonSessionServlet(
078: HttpSession session) {
079: return ((SessionDispatcher) SessionDispatchers.get(0))
080: .getSessionServlet(session);
081: }
082:
083: public PseudoServlet getSessionServlet(HttpSession session) {
084: return (PseudoServlet) sessionBoundServers.get(session.getId());
085: }
086:
087: protected abstract PseudoServlet newServlet(HttpSession session,
088: Listener.Monitor sessionMonitor) throws Exception;
089:
090: public static class Listener implements HttpSessionListener,
091: ServletContextListener {
092: private static Map sessionMonitors = new HashMap();
093: private boolean run = true;
094:
095: public void sessionCreated(HttpSessionEvent event) {
096: HttpSession session = event.getSession();
097: sessionMonitors.put(session, new Monitor(session));
098:
099: Iterator i = SessionDispatchers.iterator();
100: while (i.hasNext()) {
101: try {
102: SessionDispatcher sessionDispatcher = (SessionDispatcher) i
103: .next();
104: sessionDispatcher.sessionCreated(session);
105: } catch (Exception e) {
106: new RuntimeException(e);
107: }
108: }
109: }
110:
111: public void sessionShutdown(HttpSession session) {
112: Iterator i = SessionDispatchers.iterator();
113: while (i.hasNext()) {
114: try {
115: SessionDispatcher sessionDispatcher = (SessionDispatcher) i
116: .next();
117: sessionDispatcher.sessionShutdown(session);
118: } catch (Exception e) {
119: new RuntimeException(e);
120: }
121: }
122: session.invalidate();
123: }
124:
125: public void sessionDestroyed(HttpSessionEvent event) {
126: HttpSession session = event.getSession();
127:
128: Iterator i = SessionDispatchers.iterator();
129: while (i.hasNext()) {
130: try {
131: SessionDispatcher sessionDispatcher = (SessionDispatcher) i
132: .next();
133: sessionDispatcher.sessionDestroyed(session);
134: } catch (Exception e) {
135: new RuntimeException(e);
136: }
137: }
138: }
139:
140: public void contextInitialized(
141: ServletContextEvent servletContextEvent) {
142: Thread monitor = new Thread("Session Monitor") {
143: public void run() {
144: while (run) {
145: try {
146: //iterate over the sessions using a copying iterator
147: Iterator iterator = new ArrayList(
148: sessionMonitors.values())
149: .iterator();
150: while (iterator.hasNext()) {
151: final Monitor sessionMonitor = (Monitor) iterator
152: .next();
153: sessionMonitor.shutdownIfExpired();
154: }
155:
156: Thread.sleep(10000);
157: } catch (InterruptedException e) {
158: //ignore interrupts
159: }
160: }
161: }
162: };
163: monitor.setDaemon(true);
164: monitor.start();
165: }
166:
167: public void contextDestroyed(
168: ServletContextEvent servletContextEvent) {
169: run = false;
170: }
171:
172: public static Monitor lookupSessionMonitor(HttpSession session) {
173: return (Monitor) sessionMonitors.get(session);
174: }
175:
176: public class Monitor {
177: private HttpSession session;
178: private long lastAccess;
179:
180: private Monitor(HttpSession session) {
181: this .session = session;
182: this .lastAccess = session.getLastAccessedTime();
183: }
184:
185: public void touchSession() {
186: lastAccess = System.currentTimeMillis();
187: }
188:
189: public boolean isExpired() {
190: long elapsedInterval = System.currentTimeMillis()
191: - lastAccess;
192: long maxInterval = session.getMaxInactiveInterval() * 1000;
193: //shutdown the session a bit (15s) before session actually expires
194: return elapsedInterval + 15000 > maxInterval;
195: }
196:
197: public void shutdown() {
198: try {
199: sessionMonitors.remove(session);
200: sessionShutdown(session);
201: } catch (IllegalStateException e) {
202: //session was already invalidated by the container
203: } catch (Throwable t) {
204: //just inform that something went wrong
205: Log.warn("Failed to monitor session expiry", t);
206: }
207: }
208:
209: public void shutdownIfExpired() {
210: if (isExpired()) {
211: shutdown();
212: }
213: }
214: }
215: }
216: }
|