[Winstone-devel] winstone/src/java/winstone LocalStrings.properties, 1.48, 1.49 WinstoneSession.jav
Status: Beta
Brought to you by:
rickknowles
Update of /cvsroot/winstone/winstone/src/java/winstone In directory sc8-pr-cvs9.sourceforge.net:/tmp/cvs-serv16703/src/java/winstone Modified Files: LocalStrings.properties WinstoneSession.java RequestHandlerThread.java ObjectPool.java WebAppConfiguration.java WinstoneRequest.java Log Message: Bumped the version no to 0.9.5-cvs, and added session persistence across restarts. Disabled by default, and incurs a performance hit, but if you enable --useSavedSessions, http sessions will be saved after each request, and loaded on the container restart. Index: LocalStrings.properties =================================================================== RCS file: /cvsroot/winstone/winstone/src/java/winstone/LocalStrings.properties,v retrieving revision 1.48 retrieving revision 1.49 diff -C2 -d -r1.48 -r1.49 *** LocalStrings.properties 12 Aug 2006 07:33:11 -0000 1.48 --- LocalStrings.properties 25 Aug 2006 17:04:59 -0000 1.49 *************** *** 1,3 **** ! ServerVersion=Winstone Servlet Engine v0.8.2-cvs WebAppConfig.DefaultMimeTypes=jpg=image/jpeg:jpeg=image/jpeg:gif=image/gif:css=text/css:js=text/javascript:txt=text/plain --- 1,3 ---- ! ServerVersion=Winstone Servlet Engine v0.9.5-cvs WebAppConfig.DefaultMimeTypes=jpg=image/jpeg:jpeg=image/jpeg:gif=image/gif:css=text/css:js=text/javascript:txt=text/plain *************** *** 45,48 **** --- 45,50 ---- WebAppConfig.BadFilterMapping=Error in filter mapping - no pattern and no servlet name for filter [#0] WebAppConfig.InvalidatedSessions=Invalidating [#0] sessions due to excessive inactivity + WebAppConfig.ErrorLoadingSession=Error loading session from temp space - skipping. Error: + WebAppConfig.RestoredSession=Successfully restored session id [#0] from temp space Mapping.InvalidMount=WebAppConfig: Invalid pattern mount for [#0] pattern [#1] - ignoring *************** *** 94,97 **** --- 96,100 ---- WinstoneSession.SkippingNotSerializable=Web application is marked distributable, but session object [#0] (class [#1]) does not extend java.io.Serializable - this variable is being ignored by session transfer WinstoneSession.InvalidatedSession=Session has been invalidated + WinstoneSession.ErrorSavingSession=Error saving the session to temp space. Error: WinstoneOutputStream.CommittedBytes=Written [#0] bytes to response body Index: WebAppConfiguration.java =================================================================== RCS file: /cvsroot/winstone/winstone/src/java/winstone/WebAppConfiguration.java,v retrieving revision 1.42 retrieving revision 1.43 diff -C2 -d -r1.42 -r1.43 *** WebAppConfiguration.java 25 Aug 2006 11:53:25 -0000 1.42 --- WebAppConfiguration.java 25 Aug 2006 17:04:59 -0000 1.43 *************** *** 8,13 **** --- 8,15 ---- import java.io.File; + import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; + import java.io.ObjectInputStream; import java.io.PrintWriter; import java.io.StringWriter; *************** *** 192,195 **** --- 194,201 ---- } + public static boolean useSavedSessions(Map args) { + return booleanArg(args, "useSavedSessions", false); + } + /** * Constructor. This parses the xml and sets up for basic routing *************** *** 886,889 **** --- 892,900 ---- if (this.contextStartupError == null) { + // Load sessions if enabled + if (useSavedSessions(startupArgs)) { + loadSessions(); + } + // Initialise all the filters for (Iterator i = this.filterInstances.values().iterator(); i.hasNext();) { *************** *** 1265,1275 **** */ public WinstoneSession makeNewSession(String sessionId) { ! WinstoneSession ws = new WinstoneSession(sessionId, this, (this.cluster != null)); setSessionListeners(ws); ! if ((this.sessionTimeout != null) ! && (this.sessionTimeout.intValue() > 0)) ws.setMaxInactiveInterval(this.sessionTimeout.intValue() * 60); ! else ws.setMaxInactiveInterval(-1); ws.setLastAccessedDate(System.currentTimeMillis()); ws.sendCreatedNotifies(); --- 1276,1287 ---- */ public WinstoneSession makeNewSession(String sessionId) { ! WinstoneSession ws = new WinstoneSession(sessionId); ! ws.setWebAppConfiguration(this, (this.cluster != null)); setSessionListeners(ws); ! if ((this.sessionTimeout != null) && (this.sessionTimeout.intValue() > 0)) { ws.setMaxInactiveInterval(this.sessionTimeout.intValue() * 60); ! } else { ws.setMaxInactiveInterval(-1); + } ws.setLastAccessedDate(System.currentTimeMillis()); ws.sendCreatedNotifies(); *************** *** 1318,1322 **** for (Iterator i = allSessions.iterator(); i.hasNext(); ) { WinstoneSession session = (WinstoneSession) i.next(); ! if (!session.isNew() && session.isUnsedByRequests() && session.isExpired()) { session.invalidate(); expiredCount++; --- 1330,1334 ---- for (Iterator i = allSessions.iterator(); i.hasNext(); ) { WinstoneSession session = (WinstoneSession) i.next(); ! if (!session.isNew() && session.isUnusedByRequests() && session.isExpired()) { session.invalidate(); expiredCount++; *************** *** 1334,1337 **** --- 1346,1388 ---- session.setSessionListeners(this.sessionListeners); } + + public File getSessionTempDir() { + File tmpDir = (File) this.attributes.get("javax.servlet.context.tempdir"); + File sessionsDir = new File(tmpDir, "WEB-INF/winstoneSessions"); + sessionsDir.mkdirs(); + return sessionsDir; + } + + private void loadSessions() { + // Iterate through the files in the dir, instantiate and then add to the sessions set + File possibleSessionFiles[] = getSessionTempDir().listFiles(); + for (int n = 0; n < possibleSessionFiles.length; n++) { + if (possibleSessionFiles[n].getName().endsWith(".ser")) { + InputStream in = null; + ObjectInputStream objIn = null; + try { + in = new FileInputStream(possibleSessionFiles[n]); + objIn = new ObjectInputStream(in); + WinstoneSession session = (WinstoneSession) objIn.readObject(); + session.setWebAppConfiguration(this, (this.cluster != null)); + setSessionListeners(session); + this.sessions.put(session.getId(), session); + Logger.log(Logger.DEBUG, Launcher.RESOURCES, + "WebAppConfig.RestoredSession", session.getId()); + } catch (Throwable err) { + Logger.log(Logger.ERROR, Launcher.RESOURCES, + "WebAppConfig.ErrorLoadingSession", err); + } finally { + if (objIn != null) { + try {objIn.close();} catch (IOException err) {} + } + if (in != null) { + try {in.close();} catch (IOException err) {} + } + possibleSessionFiles[n].delete(); + } + } + } + } public void removeServletConfigurationAndMappings(ServletConfiguration config) { Index: ObjectPool.java =================================================================== RCS file: /cvsroot/winstone/winstone/src/java/winstone/ObjectPool.java,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** ObjectPool.java 12 Aug 2006 07:33:11 -0000 1.7 --- ObjectPool.java 25 Aug 2006 17:04:59 -0000 1.8 *************** *** 44,47 **** --- 44,48 ---- private int threadIndex = 0; private boolean simulateModUniqueId; + private boolean saveSessions; private Thread thread; *************** *** 53,56 **** --- 54,58 ---- public ObjectPool(Map args) throws IOException { this.simulateModUniqueId = WebAppConfiguration.booleanArg(args, "simulateModUniqueId", false); + this.saveSessions = WebAppConfiguration.useSavedSessions(args); // Build the initial pool of handler threads *************** *** 82,86 **** this.unusedRequestHandlerThreads .add(new RequestHandlerThread(this, ! this.threadIndex++, this.simulateModUniqueId)); } --- 84,89 ---- this.unusedRequestHandlerThreads .add(new RequestHandlerThread(this, ! this.threadIndex++, this.simulateModUniqueId, ! this.saveSessions)); } *************** *** 161,165 **** else if (this.usedRequestHandlerThreads.size() < MAX_REQUEST_HANDLERS_IN_POOL) { rh = new RequestHandlerThread(this, ! this.threadIndex++, this.simulateModUniqueId); this.usedRequestHandlerThreads.add(rh); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, --- 164,169 ---- else if (this.usedRequestHandlerThreads.size() < MAX_REQUEST_HANDLERS_IN_POOL) { rh = new RequestHandlerThread(this, ! this.threadIndex++, this.simulateModUniqueId, ! this.saveSessions); this.usedRequestHandlerThreads.add(rh); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, *************** *** 189,193 **** if (this.usedRequestHandlerThreads.size() < MAX_REQUEST_HANDLERS_IN_POOL) { rh = new RequestHandlerThread(this, ! this.threadIndex++, this.simulateModUniqueId); this.usedRequestHandlerThreads.add(rh); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, --- 193,198 ---- if (this.usedRequestHandlerThreads.size() < MAX_REQUEST_HANDLERS_IN_POOL) { rh = new RequestHandlerThread(this, ! this.threadIndex++, this.simulateModUniqueId, ! this.saveSessions); this.usedRequestHandlerThreads.add(rh); Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, Index: RequestHandlerThread.java =================================================================== RCS file: /cvsroot/winstone/winstone/src/java/winstone/RequestHandlerThread.java,v retrieving revision 1.19 retrieving revision 1.20 diff -C2 -d -r1.19 -r1.20 *** RequestHandlerThread.java 12 Aug 2006 07:33:11 -0000 1.19 --- RequestHandlerThread.java 25 Aug 2006 17:04:59 -0000 1.20 *************** *** 36,39 **** --- 36,40 ---- private long requestStartTime; private boolean simulateModUniqueId; + private boolean saveSessions; // private Object processingMonitor = new Boolean(true); *************** *** 43,49 **** */ public RequestHandlerThread(ObjectPool objectPool, int threadIndex, ! boolean simulateModUniqueId) { this.objectPool = objectPool; this.simulateModUniqueId = simulateModUniqueId; this.threadName = Launcher.RESOURCES.getString( "RequestHandlerThread.ThreadName", "" + threadIndex); --- 44,51 ---- */ public RequestHandlerThread(ObjectPool objectPool, int threadIndex, ! boolean simulateModUniqueId, boolean saveSessions) { this.objectPool = objectPool; this.simulateModUniqueId = simulateModUniqueId; + this.saveSessions = saveSessions; this.threadName = Launcher.RESOURCES.getString( "RequestHandlerThread.ThreadName", "" + threadIndex); *************** *** 162,166 **** // Set last accessed time on session as start of this // request ! req.markSessionsAsRequestFinished(this.requestStartTime); // send request listener notifies --- 164,168 ---- // Set last accessed time on session as start of this // request ! req.markSessionsAsRequestFinished(this.requestStartTime, this.saveSessions); // send request listener notifies Index: WinstoneRequest.java =================================================================== RCS file: /cvsroot/winstone/winstone/src/java/winstone/WinstoneRequest.java,v retrieving revision 1.31 retrieving revision 1.32 diff -C2 -d -r1.31 -r1.32 *** WinstoneRequest.java 25 Aug 2006 14:27:03 -0000 1.31 --- WinstoneRequest.java 25 Aug 2006 17:04:59 -0000 1.32 *************** *** 1324,1332 **** } ! public void markSessionsAsRequestFinished(long lastAccessedTime) { for (Iterator i = this.usedSessions.iterator(); i.hasNext(); ) { WinstoneSession session = (WinstoneSession) i.next(); session.setLastAccessedDate(lastAccessedTime); session.removeUsed(this); } this.usedSessions.clear(); --- 1324,1333 ---- } ! public void markSessionsAsRequestFinished(long lastAccessedTime, boolean saveSessions) { for (Iterator i = this.usedSessions.iterator(); i.hasNext(); ) { WinstoneSession session = (WinstoneSession) i.next(); session.setLastAccessedDate(lastAccessedTime); session.removeUsed(this); + session.saveToTemp(); } this.usedSessions.clear(); Index: WinstoneSession.java =================================================================== RCS file: /cvsroot/winstone/winstone/src/java/winstone/WinstoneSession.java,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** WinstoneSession.java 12 Aug 2006 07:33:11 -0000 1.8 --- WinstoneSession.java 25 Aug 2006 17:04:59 -0000 1.9 *************** *** 7,11 **** --- 7,15 ---- package winstone; + import java.io.File; + import java.io.FileOutputStream; import java.io.IOException; + import java.io.ObjectOutputStream; + import java.io.OutputStream; import java.io.Serializable; import java.util.ArrayList; *************** *** 50,55 **** private HttpSessionActivationListener sessionActivationListeners[]; private boolean distributable; - private AuthenticationPrincipal authenticatedUser; - private WinstoneRequest cachedRequest; private Object sessionMonitor = new Boolean(true); private Set requestsUsingMe; --- 54,57 ---- *************** *** 58,65 **** * Constructor */ ! public WinstoneSession(String sessionId, WebAppConfiguration webAppConfig, ! boolean distributable) { this.sessionId = sessionId; - this.webAppConfig = webAppConfig; this.sessionData = new HashMap(); this.requestsUsingMe = new HashSet(); --- 60,65 ---- * Constructor */ ! public WinstoneSession(String sessionId) { this.sessionId = sessionId; this.sessionData = new HashMap(); this.requestsUsingMe = new HashSet(); *************** *** 67,73 **** this.isNew = true; this.isInvalidated = false; - this.distributable = distributable; } public void sendCreatedNotifies() { // Notify session listeners of new session --- 67,77 ---- this.isNew = true; this.isInvalidated = false; } + public void setWebAppConfiguration(WebAppConfiguration webAppConfig, boolean distributable) { + this.webAppConfig = webAppConfig; + this.distributable = distributable; + } + public void sendCreatedNotifies() { // Notify session listeners of new session *************** *** 110,114 **** } ! public boolean isUnsedByRequests() { return this.requestsUsingMe.isEmpty(); } --- 114,118 ---- } ! public boolean isUnusedByRequests() { return this.requestsUsingMe.isEmpty(); } *************** *** 250,269 **** } - public WinstoneRequest getCachedRequest() { - return this.cachedRequest; - } - - public void setCachedRequest(WinstoneRequest req) { - this.cachedRequest = req; - } - - public AuthenticationPrincipal getAuthenticatedUser() { - return this.authenticatedUser; - } - - public void setAuthenticatedUser(AuthenticationPrincipal user) { - this.authenticatedUser = user; - } - public int getMaxInactiveInterval() { return this.maxInactivePeriod; --- 254,257 ---- *************** *** 336,340 **** public void activate(WebAppConfiguration webAppConfig) { this.webAppConfig = webAppConfig; - this.cachedRequest = null; webAppConfig.setSessionListeners(this); --- 324,327 ---- *************** *** 348,351 **** --- 335,365 ---- } } + + /** + * Save this session to the temp dir defined for this webapp + */ + public void saveToTemp() { + File toDir = this.webAppConfig.getSessionTempDir(); + synchronized (this.sessionMonitor) { + OutputStream out = null; + ObjectOutputStream objOut = null; + try { + File toFile = new File(toDir, this.sessionId + ".ser"); + out = new FileOutputStream(toFile, false); + objOut = new ObjectOutputStream(out); + objOut.writeObject(this); + } catch (IOException err) { + Logger.log(Logger.ERROR, Launcher.RESOURCES, + "WinstoneSession.ErrorSavingSession", err); + } finally { + if (objOut != null) { + try {objOut.close();} catch (IOException err) {} + } + if (out != null) { + try {out.close();} catch (IOException err) {} + } + } + } + } /** *************** *** 364,379 **** out.writeBoolean(isNew); out.writeBoolean(distributable); - out.writeObject(authenticatedUser); // Write the map, but first remove non-serializables Map copy = new HashMap(sessionData); ! for (Iterator i = copy.keySet().iterator(); i.hasNext();) { String key = (String) i.next(); ! if (!(copy.get(key) instanceof Serializable)) ! Logger ! .log(Logger.WARNING, Launcher.RESOURCES, "WinstoneSession.SkippingNonSerializable", new String[] { key, copy.get(key).getClass().getName() }); copy.remove(key); } --- 378,393 ---- out.writeBoolean(isNew); out.writeBoolean(distributable); // Write the map, but first remove non-serializables Map copy = new HashMap(sessionData); ! Set keys = new HashSet(copy.keySet()); ! for (Iterator i = keys.iterator(); i.hasNext();) { String key = (String) i.next(); ! if (!(copy.get(key) instanceof Serializable)) { ! Logger.log(Logger.WARNING, Launcher.RESOURCES, "WinstoneSession.SkippingNonSerializable", new String[] { key, copy.get(key).getClass().getName() }); + } copy.remove(key); } *************** *** 402,409 **** this.isNew = in.readBoolean(); this.distributable = in.readBoolean(); - this.authenticatedUser = (AuthenticationPrincipal) in.readObject(); // Read the map this.sessionData = new Hashtable(); int entryCount = in.readInt(); for (int n = 0; n < entryCount; n++) { --- 416,423 ---- this.isNew = in.readBoolean(); this.distributable = in.readBoolean(); // Read the map this.sessionData = new Hashtable(); + this.requestsUsingMe = new HashSet(); int entryCount = in.readInt(); for (int n = 0; n < entryCount; n++) { |