001: package org.mortbay.jetty.servlet;
002:
003: import java.io.IOException;
004: import java.io.ObjectInputStream;
005: import java.io.ObjectOutputStream;
006: import java.io.Serializable;
007: import java.util.HashMap;
008: import java.util.List;
009: import java.util.Map;
010:
011: import javax.servlet.ServletContext;
012: import javax.servlet.http.HttpServletRequest;
013: import javax.servlet.http.HttpSession;
014:
015: import org.mortbay.jetty.Connector;
016: import org.mortbay.jetty.Handler;
017: import org.mortbay.jetty.Server;
018: import org.mortbay.jetty.SessionIdManager;
019: import org.mortbay.jetty.handler.ContextHandler;
020: import org.mortbay.jetty.handler.ContextHandlerCollection;
021: import org.mortbay.jetty.handler.DefaultHandler;
022: import org.mortbay.jetty.handler.HandlerCollection;
023: import org.mortbay.jetty.nio.SelectChannelConnector;
024: import org.mortbay.jetty.security.HashUserRealm;
025: import org.mortbay.jetty.webapp.WebAppContext;
026:
027: import net.sf.ehcache.Ehcache;
028: import net.sf.ehcache.Element;
029:
030: /* ------------------------------------------------------------ */
031: /**
032: * A session manager that uses ehcache in front of a pluggable session store.
033: *
034: * THIS IS PRE-ALPHA CODE - only checked in for more developement!
035: *
036: * @author nik
037: *
038: */
039: public class CacheSessionManager extends AbstractSessionManager
040: implements Serializable {
041: protected String _cacheKey;
042: transient CacheSessionIdManager _cacheIdManager;
043: transient Ehcache _sessionCache;
044: transient Store _sessionStore;
045:
046: /* ------------------------------------------------------------ */
047: public void doStart() throws Exception {
048: super .doStart();
049: SessionIdManager sid = getIdManager();
050: if (!(sid instanceof CacheSessionIdManager))
051: throw new IllegalStateException("Non cached ID manager:"
052: + sid);
053: _cacheIdManager = (CacheSessionIdManager) sid;
054:
055: _cacheKey = _context.getContextPath();
056: if (_context.getContextHandler().getVirtualHosts() != null
057: && _context.getContextHandler().getVirtualHosts().length > 0)
058: _cacheKey = _cacheKey + "@"
059: + _context.getContextHandler().getVirtualHosts()[0];
060: _cacheKey = _cacheKey.replace('/', '_');
061:
062: synchronized (_cacheIdManager) {
063: _sessionCache = _cacheIdManager._cacheManager
064: .getEhcache(_cacheKey);
065: if (_sessionCache == null) {
066:
067: // just create a cache with the default settings of the cacheIdManager
068: _cacheIdManager._cacheManager.addCache(_cacheKey);
069: _sessionCache = _cacheIdManager._cacheManager
070: .getEhcache(_cacheKey);
071:
072: // XXX Changed my mind about self populating caches.
073: // they always create an element - which is not what we want.
074:
075: }
076: }
077:
078: if (_sessionStore != null) {
079: _sessionStore.setContext(_context.getContextPath());
080: }
081: }
082:
083: public void setStore(Store store) {
084: _sessionStore = store;
085: }
086:
087: /* ------------------------------------------------------------ */
088: public Map getSessionMap() {
089: // Not supported in this impl
090: return null;
091: }
092:
093: /* ------------------------------------------------------------ */
094: public int getSessions() {
095: // TODO this is not exactly correct and we need to think about the
096: // diskstore and sessions not on the node. Maybe this is only sessions
097: // this node??
098: return _sessionCache.getSize();
099: }
100:
101: /* ------------------------------------------------------------ */
102: protected void addSession(Session session) {
103: // OK - changing my mind here.... perhaps the whole
104: // session is in the cache!
105: _sessionCache.put(new Element(session.getClusterId(), session));
106:
107: // TODO - maybe put the Element as a transient in the Session
108: // instance, so it can be used for last access times, isValid etc.
109: }
110:
111: /* ------------------------------------------------------------ */
112: protected Session getSession(String idInCluster) {
113: Element sessionElement = _sessionCache.get(idInCluster);
114: Session session = null;
115:
116: if (sessionElement == null || sessionElement.isExpired()) {
117: session = (Session) _sessionStore.get(idInCluster);
118: if (session == null) {
119: return null;
120: }
121: ((EHSession) session).setServletContext(_context);
122: sessionElement = new Element(session.getClusterId(),
123: session);
124: _sessionCache.put(sessionElement);
125: } else {
126: session = (Session) sessionElement.getValue();
127: }
128:
129: if (session != null) {
130: EHSession ehSession = (EHSession) session;
131: ehSession.setSessionCacheElement(sessionElement);
132: }
133:
134: return session;
135: }
136:
137: /* ------------------------------------------------------------ */
138: protected void invalidateSessions() {
139: // TODO Auto-generated method stub
140: }
141:
142: /* ------------------------------------------------------------ */
143: protected Session newSession(HttpServletRequest request) {
144: return new EHSession(request);
145: }
146:
147: /* ------------------------------------------------------------ */
148: protected void removeSession(String idInCluster) {
149: _sessionCache.remove(idInCluster);
150: }
151:
152: public void complete(HttpSession session) {
153: EHSession ehSession = (EHSession) session;
154: if (ehSession._dirty)
155: _sessionStore.add(ehSession.getClusterId(),
156: (EHSession) session);
157: }
158:
159: /* ------------------------------------------------------------ */
160: /* ------------------------------------------------------------ */
161: /* ------------------------------------------------------------ */
162: protected class EHSession extends AbstractSessionManager.Session {
163: private boolean _dirty = false;
164: transient Element _sessionCacheElement;
165:
166: /* ------------------------------------------------------------- */
167: protected EHSession(HttpServletRequest request) {
168: super (request);
169: }
170:
171: /* ------------------------------------------------------------ */
172: protected Map newAttributeMap() {
173: return new HashMap(3);
174: }
175:
176: protected void setSessionCacheElement(
177: Element sessionCacheElement) {
178: _sessionCacheElement = sessionCacheElement;
179: }
180:
181: private void setServletContext(ContextHandler.SContext context) {
182: _context = context;
183: }
184:
185: private void readObject(ObjectInputStream in)
186: throws ClassNotFoundException, IOException {
187: in.defaultReadObject();
188: _dirty = false;
189: }
190:
191: public synchronized void setAttribute(String name, Object value) {
192: super .setAttribute(name, value);
193: _dirty = true;
194: }
195: }
196:
197: public interface Store {
198: Object get(String id);
199:
200: void add(String id, Serializable serializable);
201:
202: void remove(String id);
203:
204: List getKeys();
205:
206: void setContext(String contextName);
207: }
208:
209: /* ------------------------------------------------------------ */
210: /* ------------------------------------------------------------ */
211: /* ------------------------------------------------------------ */
212: // TODO remove this test main eventually when not needed for simple testing.
213: public static void main(String[] args) throws Exception {
214: String jetty_home = System.getProperty("jetty.home");
215: if (jetty_home == null)
216: jetty_home = "../..";
217:
218: Server server = new Server();
219: SelectChannelConnector connector = new SelectChannelConnector();
220: connector.setPort(8080);
221: server.setConnectors(new Connector[] { connector });
222: server.setSessionIdManager(new CacheSessionIdManager(jetty_home
223: + "/sessions"));
224:
225: HandlerCollection handlers = new HandlerCollection();
226: ContextHandlerCollection contexts = new ContextHandlerCollection();
227:
228: WebAppContext[] wah = new WebAppContext[3];
229:
230: for (int i = 0; i < 3; i++) {
231: SessionHandler sessionHandler = new SessionHandler();
232: CacheSessionManager cacheSessionManager = new CacheSessionManager();
233: cacheSessionManager.setSessionHandler(sessionHandler);
234: cacheSessionManager.setStore(new FileStore(jetty_home
235: + "/sessions"));
236: sessionHandler.setSessionManager(cacheSessionManager);
237:
238: wah[i] = new WebAppContext(null, sessionHandler, null, null);
239: wah[i].setContextPath("/test" + (i == 0 ? "" : ("" + i)));
240: wah[i].setResourceBase(jetty_home + "/webapps/test");
241: }
242:
243: contexts.setHandlers(wah);
244: handlers.setHandlers(new Handler[] { contexts,
245: new DefaultHandler() });
246: server.setHandler(handlers);
247:
248: HashUserRealm hur = new HashUserRealm();
249: hur.setName("Test Realm");
250: hur.setConfig(jetty_home + "/etc/realm.properties");
251: wah[0].getSecurityHandler().setUserRealm(hur);
252:
253: server.start();
254: server.join();
255: }
256:
257: }
|