You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@locus.apache.org on 2000/09/25 08:10:56 UTC
cvs commit: jakarta-tomcat/src/facade22/org/apache/tomcat/facade HttpSessionFacade.java Servlet22Manager.java
costin 00/09/24 23:10:55
Modified: src/share/org/apache/tomcat/session ServerSession.java
ServerSessionManager.java SessionSerializer.java
StandardSessionInterceptor.java
src/facade22/org/apache/tomcat/facade HttpSessionFacade.java
Servlet22Manager.java
Added: src/share/org/apache/tomcat/util/threads Expirer.java
TimeStamp.java
Removed: src/share/org/apache/tomcat/session TimeStamp.java
Log:
- moved the code that handle expiration in a tomcat.util class.
It will be used by ContextManager to unload unused Contexts and servlets,
and may be used for other tasks ( it's a general-purpose tool )
- same refactoring as in core - replaced indirect calls, methods and properties
moved to the object where it belongs, split complex objects in simpler ones,
moved generic code in util.
- the session manager code is now much narrowly focused, and it should be
easier ( in 3.4 + ) to add more sophisticated managers ( database, etc). It's
also much cleanly separated from upper layer.
( some thing may be broken, but most of the refactoring is done.
)
Revision Changes Path
1.6 +21 -85 jakarta-tomcat/src/share/org/apache/tomcat/session/ServerSession.java
Index: ServerSession.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/ServerSession.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- ServerSession.java 2000/09/24 23:03:13 1.5
+++ ServerSession.java 2000/09/25 06:10:48 1.6
@@ -66,7 +66,7 @@
import java.util.Hashtable;
import java.util.Vector;
import org.apache.tomcat.util.*;
-import javax.servlet.http.*;
+import org.apache.tomcat.util.threads.*;
/**
* Server representation of a Session.
@@ -88,10 +88,17 @@
TimeStamp ts=new TimeStamp();
boolean distributable=false;
-
- public ServerSession() {
+ ServerSessionManager ssm;
+
+ /** Only ServerSessionManager can create ServerSessions
+ */
+ ServerSession(ServerSessionManager ssm) {
+ this.ssm=ssm;
}
+ public ServerSessionManager getSessionManager() {
+ return ssm;
+ }
// ----------------------------------------------------- Session Properties
/** The time stamp associated with this session
*/
@@ -106,45 +113,6 @@
return id;
}
- public boolean isDistributable() {
- return distributable;
- }
-
- public void setDistributable( boolean b ) {
- distributable=b;
- }
-
- // --------------------
-
- /**
- * Perform the internal processing required to invalidate this session,
- * without triggering an exception if the session has already expired.
- */
- public void expire() {
-
- // Remove this session from our manager's active sessions
-// if (manager != null)
-// manager.remove(this);
-
- // Unbind any objects associated with this session
- Vector results = new Vector();
- Enumeration attrs = getAttributeNames();
- while (attrs.hasMoreElements()) {
- String attr = (String) attrs.nextElement();
- results.addElement(attr);
- }
- Enumeration names = results.elements();
- while (names.hasMoreElements()) {
- String name = (String) names.nextElement();
- removeAttribute(name);
- }
-
- // Mark this session as invalid
- ts.setValid(false);
-
- }
-
-
// -------------------- Attribute access --------------------
public Object getAttribute(String name) {
@@ -160,55 +128,23 @@
return attributes.size();
}
- public void removeAttribute(String name) {
- synchronized (attributes) {
- Object object = attributes.get(name);
- if (object == null)
- return;
- attributes.remove(name);
- // System.out.println( "Removing attribute " + name );
-// if (object instanceof HttpSessionBindingListener) {
-// ((HttpSessionBindingListener) object).valueUnbound
-// (new HttpSessionBindingEvent((HttpSession) this, name));
-// }
+ public void removeAllAttributes() {
+ Enumeration attrs = getAttributeNames();
+ while (attrs.hasMoreElements()) {
+ String attr = (String) attrs.nextElement();
+ removeAttribute(attr);
}
}
- public void setAttribute(String name, Object value) {
- synchronized (attributes) {
- removeAttribute(name);
- attributes.put(name, value);
-// if (value instanceof HttpSessionBindingListener)
-// ((HttpSessionBindingListener) value).valueBound
-// (new HttpSessionBindingEvent((HttpSession) this, name));
- }
+ public void removeAttribute(String name) {
+ // Hashtable is already synchronized
+ attributes.remove(name);
}
-
-
- /** Normal serialization can be used for this object, but before
- serializing you _must_ call prepareSerialize() to remove all
- non-serializable attributes and notify about their removal.
- */
- private void prepareSerialize()
- {
- for (Enumeration e = attributes.keys(); e.hasMoreElements() ; ) {
- String key = (String) e.nextElement();
- Object value = attributes.get(key);
- if (! ( value instanceof Serializable)) {
- if (value instanceof HttpSessionBindingListener ) {
-// try {
-// ((HttpSessionBindingListener)value)
-// .valueUnbound(new
-// HttpSessionBindingEvent(this, key));
-// } catch (Exception f) {
-// // ignored
-// }
- }
- attributes.remove( key );
- }
- }
+ public void setAttribute(String name, Object value) {
+ attributes.put(name, value);
}
+
/**
* Release all object references, and initialize instance variables, in
1.7 +57 -158 jakarta-tomcat/src/share/org/apache/tomcat/session/ServerSessionManager.java
Index: ServerSessionManager.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/ServerSessionManager.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- ServerSessionManager.java 2000/09/24 23:03:13 1.6
+++ ServerSessionManager.java 2000/09/25 06:10:49 1.7
@@ -69,28 +69,14 @@
import org.apache.tomcat.util.*;
import org.apache.tomcat.util.threads.*;
import org.apache.tomcat.helper.*;
-import org.apache.tomcat.core.Request;
+import org.apache.tomcat.core.*;
/**
*
*
*/
-public final class ServerSessionManager implements ThreadPoolRunnable
+public final class ServerSessionManager
{
- // ----------------------------------------------------- Instance Variables
- /**
- * The distributable flag for Sessions created by this Manager. If this
- * flag is set to <code>true</code>, any user attributes added to a
- * session controlled by this Manager must be Serializable.
- */
- protected boolean distributable;
-
- /**
- * The default maximum inactive interval for Sessions created by
- * this Manager.
- */
- protected int maxInactiveInterval = 60;
-
/** The set of previously recycled Sessions for this Manager.
*/
protected SimplePool recycled = new SimplePool();
@@ -101,6 +87,7 @@
*/
protected Hashtable sessions = new Hashtable();
+ protected Expirer expirer;
/**
* The interval (in seconds) between checks for expired sessions.
*/
@@ -111,100 +98,53 @@
*/
protected int maxActiveSessions = -1;
- /**
- * The string manager for this package.
- */
- private static StringManager sm =
- StringManager.getManager("org.apache.tomcat.resources");
-
+ long maxInactiveInterval;
+
protected Reaper reaper;
public ServerSessionManager() {
}
- // ------------------------------------------------------------- Properties
- /**
- * Return the distributable flag for the sessions supported by
- * this Manager.
- */
- public boolean getDistributable() {
- return (this.distributable);
+ public void setExpirer( Expirer ex ) {
+ expirer = ex;
}
- /**
- * Set the distributable flag for the sessions supported by this
- * Manager. If this flag is set, all user data objects added to
- * sessions associated with this manager must implement Serializable.
- *
- * @param distributable The new distributable flag
- */
- public void setDistributable(boolean distributable) {
- this.distributable = distributable;
+ public Expirer getExpirer() {
+ return expirer;
}
-
- /**
- * Return the default maximum inactive interval (in seconds)
- * for Sessions created by this Manager.
- */
- public int getMaxInactiveInterval() {
- return (this.maxInactiveInterval);
+
+ // ------------------------------------------------------------- Properties
+ public int getMaxActiveSessions() {
+ return maxActiveSessions;
}
- /**
- * Set the default maximum inactive interval (in seconds)
- * for Sessions created by this Manager.
- *
- * @param interval The new default value
- */
- public void setMaxInactiveInterval(int interval) {
- this.maxInactiveInterval = interval;
+ public void setMaxActiveSessions(int max) {
+ maxActiveSessions = max;
}
- /**
- * Used by context to configure the session manager's inactivity timeout.
- *
- * The SessionManager may have some default session time out, the
- * Context on the other hand has it's timeout set by the deployment
- * descriptor (web.xml). This method lets the Context conforgure the
- * session manager according to this value.
- *
- * @param minutes The session inactivity timeout in minutes.
- */
- public void setSessionTimeOut(int minutes) {
- if(-1 != minutes) {
- // The manager works with seconds...
- setMaxInactiveInterval(minutes * 60);
- }
- }
+ // --------------------------------------------------------- Public Methods
- /**
- * Return the check interval (in seconds) for this Manager.
- */
- public int getCheckInterval() {
- return (this.checkInterval);
+ public void setMaxInactiveInterval( long l ) {
+ maxInactiveInterval=l;
}
-
+
/**
- * Set the check interval (in seconds) for this Manager.
- *
- * @param checkInterval The new check interval
+ * Return the default maximum inactive interval (in miliseconds)
+ * for Sessions created by this Manager. We use miliseconds
+ * because that's how the time is expressed, avoid /1000
+ * in the common code
*/
- public void setCheckInterval(int checkInterval) {
- this.checkInterval = checkInterval;
+ public long getMaxInactiveInterval() {
+ return maxInactiveInterval;
}
- public int getMaxActiveSessions() {
- return maxActiveSessions;
- }
- public void setMaxActiveSessions(int max) {
- maxActiveSessions = max;
+ Hashtable getSessions() {
+ return sessions;
}
-
- // --------------------------------------------------------- Public Methods
-
- public Hashtable getSessions() {
- return this.sessions;
+
+ void setSessions(Hashtable s) {
+ sessions=s;
}
public ServerSession findSession(String id) {
@@ -212,6 +152,19 @@
return (ServerSession)sessions.get(id);
}
+ /**
+ * Remove this Session from the active Sessions for this Manager.
+ *
+ * @param session Session to be removed
+ */
+ public void removeSession(ServerSession session) {
+ sessions.remove(session.getId().toString());
+ recycled.put(session);
+ session.removeAllAttributes();
+ expirer.removeManagedObject( session.getTimeStamp());
+ session.getTimeStamp().setValid(false);
+ }
+
public ServerSession getNewSession() {
if ((maxActiveSessions >= 0) &&
(sessions.size() >= maxActiveSessions))
@@ -220,10 +173,10 @@
// Recycle or create a Session instance
ServerSession session = (ServerSession)recycled.get();
if (session == null) {
- session = new ServerSession();
+ session = new ServerSession(this);
recycled.put( session );
}
-
+
// XXX can return MessageBytes !!!
String newId=SessionUtil.generateSessionId();
@@ -232,88 +185,34 @@
ServerSession oldS=findSession( newId );
if( oldS!=null) {
// that's what the original code did
- remove( oldS );
+ removeSession( oldS );
}
// Initialize the properties of the new session and return it
session.getId().setString( newId );
-
- session.getTimeStamp().setNew(true);
- session.getTimeStamp().setValid(true);
- session.getTimeStamp().setCreationTime(System.currentTimeMillis());
- session.getTimeStamp().setMaxInactiveInterval(maxInactiveInterval);
+
+ TimeStamp ts=session.getTimeStamp();
+ ts.setNew(true);
+ ts.setValid(true);
+
+ ts.setCreationTime(System.currentTimeMillis());
+ ts.setMaxInactiveInterval(getMaxInactiveInterval());
+ session.getTimeStamp().setParent( session );
// System.out.println("New session: " + newId );
sessions.put( newId, session );
-
+ expirer.addManagedObject( session.getTimeStamp());
return (session);
}
- public void handleReload(Request req, ClassLoader newLoader) {
- sessions = SessionSerializer.doSerialization( newLoader, sessions);
- }
-
- public void start() {
- // Start the background reaper thread
- reaper=new Reaper("StandardManager");
- reaper.addCallback( this, checkInterval * 1000 );
- reaper.startReaper();
- }
-
- public void stop() {
- reaper.stopReaper();
-
- // expire all active sessions
+ public void removeAllSessions() {
Enumeration ids = sessions.keys();
while (ids.hasMoreElements()) {
String id = (String) ids.nextElement();
ServerSession session = (ServerSession) sessions.get(id);
if (!session.getTimeStamp().isValid())
continue;
- session.expire();
- }
- }
-
- /**
- * Remove this Session from the active Sessions for this Manager.
- *
- * @param session Session to be removed
- */
- void remove(ServerSession session) {
- sessions.remove(session.getId().toString());
- recycled.put(session);
- }
-
-
- // -------------------------------------------------------- Private Methods
-
- // ThreadPoolRunnable impl
-
- public Object[] getInitData() {
- return null;
- }
-
- public void runIt( Object td[] ) {
- // System.out.println("Expiring " + this);
- long timeNow = System.currentTimeMillis();
- Enumeration ids = sessions.keys();
- while (ids.hasMoreElements()) {
- String id = (String) ids.nextElement();
- ServerSession session = (ServerSession) sessions.get(id);
- TimeStamp ts=session.getTimeStamp();
-
- if (!ts.isValid())
- continue;
-
- int maxInactiveInterval = ts.getMaxInactiveInterval();
- if (maxInactiveInterval < 0)
- continue;
-
- int timeIdle = // Truncate, do not round up
- (int) ((timeNow - ts.getLastAccessedTime()) / 1000L);
-
- if (timeIdle >= maxInactiveInterval)
- session.expire();
+ removeSession( session );
}
}
1.9 +3 -3 jakarta-tomcat/src/share/org/apache/tomcat/session/SessionSerializer.java
Index: SessionSerializer.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/SessionSerializer.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- SessionSerializer.java 2000/09/24 18:10:12 1.8
+++ SessionSerializer.java 2000/09/25 06:10:49 1.9
@@ -81,8 +81,8 @@
/**
This is the method that does the serialization.
*/
- public static final Hashtable doSerialization(ClassLoader cl,
- Hashtable sessions)
+ public static final Object doSerialization(ClassLoader cl,
+ Object sessions)
{
// get the hashtable of sessions
try {
@@ -101,7 +101,7 @@
ObjectInputStream oOut= new ACLObjectInputStream(cl, bIn);
// unserialize the sessions
- sessions = (Hashtable) oOut.readObject();
+ sessions = oOut.readObject();
return sessions;
} catch (Exception e) {
1.11 +69 -51 jakarta-tomcat/src/share/org/apache/tomcat/session/StandardSessionInterceptor.java
Index: StandardSessionInterceptor.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/StandardSessionInterceptor.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- StandardSessionInterceptor.java 2000/09/24 23:03:13 1.10
+++ StandardSessionInterceptor.java 2000/09/25 06:10:49 1.11
@@ -58,13 +58,14 @@
*/
package org.apache.tomcat.session;
-import java.io.IOException;
+import java.io.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import org.apache.tomcat.util.*;
+import org.apache.tomcat.util.threads.*;
import org.apache.tomcat.core.*;
@@ -87,13 +88,27 @@
*/
public final class StandardSessionInterceptor extends BaseInterceptor {
int manager_note;
+
+ int checkInterval = 60;
+ int maxActiveSessions = -1;
public StandardSessionInterceptor() {
}
// -------------------- Configuration properties --------------------
-
+ /**
+ * Set the check interval (in seconds) for this Manager.
+ *
+ * @param checkInterval The new check interval
+ */
+ public void setCheckInterval( int secs ) {
+ checkInterval=secs;
+ }
+
+ public void setMaxActiveSessions( int count ) {
+ maxActiveSessions=count;
+ }
// -------------------- Tomcat request events --------------------
@@ -145,15 +160,38 @@
public void reload( Request req, Context ctx ) {
ClassLoader newLoader = ctx.getClassLoader();
ServerSessionManager sM = getManager( ctx );
- sM.handleReload(req, newLoader);
- if (req.getSession(false) != null) {
- // replace the current session in the current request
- Hashtable sessions=sM.getSessions();
- HttpSession newSession =
- (HttpSession)sessions.get(req.getRequestedSessionId());
- req.setSession(newSession);
- req.setSessionId( newSession.getId());
+
+ // remove all non-serializable objects from session
+ Enumeration sessionEnum=sM.getSessions().keys();
+ while( sessionEnum.hasMoreElements() ) {
+ ServerSession session = (ServerSession)sessionEnum.nextElement();
+ Enumeration e = session.getAttributeNames();
+ while( e.hasMoreElements() ) {
+ String key = (String) e.nextElement();
+ Object value = session.getAttribute(key);
+ // XXX XXX We don't have to change loader for objects loaded
+ // by the parent loader ?
+ if (! ( value instanceof Serializable)) {
+ session.removeAttribute( key );
+ // XXX notification!!
+ }
+ }
}
+
+ // XXX We should change the loader for each object, and
+ // avoid accessing object's internals
+ // XXX PipeStream !?!
+ Hashtable orig= sM.getSessions();
+ Object newS = SessionSerializer.doSerialization( newLoader, orig);
+ sM.setSessions( (Hashtable)newS );
+
+ // Update the request session id
+ String reqId=req.getRequestedSessionId();
+ ServerSession sS=sM.findSession( reqId );
+ if ( sS != null) {
+ req.setSession(sS);
+ req.setSessionId( reqId );
+ }
}
public int newSessionRequest( Request request, Response response) {
@@ -170,26 +208,6 @@
return 0;
}
- /** Called after request - we need to release the session object.
- * This is used to prevent removal of session objects during execution,
- * and may be used by interceptors that want to limit or count the
- * sessions.
- */
- public int postService( Request rrequest, Response response ) {
- // Not used, maybe add it back later if we need to
-
- // Context ctx=rrequest.getContext();
- // if( ctx==null ) return 0;
-
- // ServerSessionManager sm= getManager( ctx );
- // HttpSession sess=(HttpSession)rrequest.getSession(false);
- // if( sess == null ) return 0;
- // sm.release( sess );
- return 0;
- }
-
-
-
//-------------------- Tomcat context events --------------------
/** Init session management stuff for this context.
@@ -200,18 +218,25 @@
if( sm == null ) {
sm=new ServerSessionManager();
- setManager(ctx, sm);
- }
-
- // init is called after all context properties are set.
- sm.setSessionTimeOut( ctx.getSessionTimeOut() );
- sm.setDistributable( ctx.isDistributable() );
-
- try {
- sm.start();
- } catch(IllegalStateException ex ) {
- throw new TomcatException( ex );
- }
+ ctx.getContainer().setNote( manager_note, sm );
+ sm.setMaxInactiveInterval( (long)ctx.getSessionTimeOut() *
+ 60 * 1000 );
+ // debug
+ sm.setMaxInactiveInterval( 60000 );
+ }
+ sm.setMaxActiveSessions( maxActiveSessions );
+
+ Expirer expirer=new Expirer();
+ expirer.setCheckInterval( checkInterval );
+ expirer.setExpireCallback( new Expirer.ExpireCallback() {
+ public void expired(TimeStamp o ) {
+ ServerSession sses=(ServerSession)o.getParent();
+ ServerSessionManager ssm=sses.getSessionManager();
+ ssm.removeSession( sses );
+ }
+ });
+ expirer.start();
+ sm.setExpirer(expirer);
}
/** Notification of context shutdown.
@@ -223,12 +248,8 @@
{
if( ctx.getDebug() > 0 ) ctx.log("Removing sessions from " + ctx );
ServerSessionManager sm=getManager(ctx);
- try {
- if( sm != null )
- sm.stop();
- } catch(IllegalStateException ex ) {
- throw new TomcatException( ex );
- }
+ sm.getExpirer().stop();
+ sm.removeAllSessions();
}
// -------------------- Internal methods --------------------
@@ -236,9 +257,6 @@
return (ServerSessionManager)ctx.getContainer().getNote(manager_note);
}
- private void setManager( Context ctx, Object sm ) {
- ctx.getContainer().setNote( manager_note, sm );
- }
}
1.1 jakarta-tomcat/src/share/org/apache/tomcat/util/threads/Expirer.java
Index: Expirer.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.util.threads;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.apache.tomcat.util.*;
import org.apache.tomcat.util.threads.*;
/**
* Expire unused objects.
*
*/
public final class Expirer implements ThreadPoolRunnable
{
// We can use Event/Listener, but this is probably simpler
// and more efficient
public static interface ExpireCallback {
public void expired( TimeStamp o );
}
private int checkInterval = 60;
private Reaper reaper;
ExpireCallback expireCallback;
public Expirer() {
}
// ------------------------------------------------------------- Properties
public int getCheckInterval() {
return checkInterval;
}
public void setCheckInterval(int checkInterval) {
this.checkInterval = checkInterval;
}
public void setExpireCallback( ExpireCallback cb ) {
expireCallback=cb;
}
// -------------------- Managed objects --------------------
static final int INITIAL_SIZE=8;
TimeStamp managedObjs[]=new TimeStamp[INITIAL_SIZE];
int managedLen=managedObjs.length;
int managedCount=0;
public void addManagedObject( TimeStamp ts ) {
synchronized( managedObjs ) {
if( managedCount > managedLen ) {
// What happens if expire is on the way ? Nothing,
// expire will do it's job on the old array ( GC magic )
// and the expired object will be marked as such
// Same thing would happen ( and did ) with Hashtable
TimeStamp newA[]=new TimeStamp[ 2 * managedLen ];
System.arraycopy( managedObjs, 0, newA, 0, managedLen);
managedObjs = newA;
}
managedObjs[managedCount++]=ts;
}
}
public void removeManagedObject( TimeStamp ts ) {
for( int i=0; i< managedCount; i++ ) {
if( ts == managedObjs[i] ) {
synchronized( managedObjs ) {
managedObjs[ i ] = managedObjs[managedCount-1];
managedCount--;
}
return;
}
}
}
// --------------------------------------------------------- Public Methods
public void start() {
// Start the background reaper thread
if( reaper==null) {
reaper=new Reaper("Expirer");
reaper.addCallback( this, checkInterval * 1000 );
}
reaper.startReaper();
}
public void stop() {
reaper.stopReaper();
}
// -------------------------------------------------------- Private Methods
// ThreadPoolRunnable impl
public Object[] getInitData() {
return null;
}
public void runIt( Object td[] ) {
long timeNow = System.currentTimeMillis();
if( dL > 2 ) debug( "Checking " + timeNow );
for( int i=0; i< managedCount; i++ ) {
TimeStamp ts=managedObjs[i];
if (ts==null || !ts.isValid())
continue;
long maxInactiveInterval = ts.getMaxInactiveInterval();
if( dL > 3 ) debug( "TS: " + maxInactiveInterval + " " +
ts.getLastAccessedTime());
if (maxInactiveInterval < 0)
continue;
long timeIdle = timeNow - ts.getLastAccessedTime();
if (timeIdle >= maxInactiveInterval) {
if( expireCallback != null ) {
if( dL > 0 )
debug( ts + " " + timeIdle + " " +
maxInactiveInterval );
expireCallback.expired( ts );
}
}
}
}
private static final int dL=0;
private void debug( String s ) {
System.out.println("Expirer: " + s );
}
}
1.1 jakarta-tomcat/src/share/org/apache/tomcat/util/threads/TimeStamp.java
Index: TimeStamp.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.util.threads;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
* Marks creation and access times, plus validity.
*
* Used for objects that expire - originally Sessions, but
* soon Contexts and Servlets ( scalability issues, large server support ).
*
* @author Costin Manolache
*/
public final class TimeStamp implements Serializable {
private long creationTime = 0L;
private long lastAccessedTime = creationTime;
private long thisAccessedTime = creationTime;
private boolean isNew = true;
private long maxInactiveInterval = -1;
private boolean isValid = false;
Object parent;
public TimeStamp() {
}
// -------------------- Active methods --------------------
/**
* Access notification. This method takes a time parameter in order
* to allow callers to efficiently manage expensive calls to
* System.currentTimeMillis()
*/
public void touch(long time) {
this.lastAccessedTime = this.thisAccessedTime;
this.thisAccessedTime = time;
this.isNew=false;
}
// -------------------- Property access --------------------
/** Returns the owner of this stamp ( the object that is
* time-stamped
*/
public void setParent( Object o ) {
parent=o;
}
public Object getParent() {
return parent;
}
public void setCreationTime(long time) {
this.creationTime = time;
this.lastAccessedTime = time;
this.thisAccessedTime = time;
}
public long getLastAccessedTime() {
return lastAccessedTime;
}
/** Inactive interval in millis - the time is computed
* in millis, convert to secs in the upper layer
*/
public long getMaxInactiveInterval() {
return maxInactiveInterval;
}
public void setMaxInactiveInterval(long interval) {
maxInactiveInterval = interval;
}
public boolean isValid() {
return isValid;
}
public void setValid(boolean isValid) {
this.isValid = isValid;
}
public boolean isNew() {
return isNew;
}
public void setNew(boolean isNew) {
this.isNew = isNew;
}
public long getCreationTime() {
return creationTime;
}
// -------------------- Maintainance --------------------
public void recycle() {
creationTime = 0L;
lastAccessedTime = 0L;
maxInactiveInterval = -1;
isNew = true;
isValid = false;
}
}
1.4 +27 -8 jakarta-tomcat/src/facade22/org/apache/tomcat/facade/HttpSessionFacade.java
Index: HttpSessionFacade.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/facade22/org/apache/tomcat/facade/HttpSessionFacade.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- HttpSessionFacade.java 2000/09/24 20:01:43 1.3
+++ HttpSessionFacade.java 2000/09/25 06:10:53 1.4
@@ -113,6 +113,7 @@
// -------------------- public facade --------------------
public String getId() {
+ checkValid();
return realSession.getId().toString();
}
@@ -151,7 +152,10 @@
*/
public void invalidate() {
checkValid();
- realSession.expire();
+ ServerSessionManager ssm=realSession.getSessionManager();
+ ssm.removeSession( realSession );
+ realSession.removeAllAttributes();
+ realSession.getTimeStamp().setValid( false );
}
/**
@@ -179,12 +183,19 @@
public void setAttribute(String name, Object value) {
checkValid();
- if (realSession.isDistributable() &&
- !(value instanceof Serializable))
- throw new IllegalArgumentException
- (sm.getString("standardSession.setAttribute.iae"));
+ ServerSessionManager ssm=realSession.getSessionManager();
+ // Original code - it's up to session manager to decide
+ // what it can handle.
+ // if (ssm.isDistributable() &&
+ // !(value instanceof Serializable))
+ // throw new IllegalArgumentException
+ // (sm.getString("standardSession.setAttribute.iae"));
realSession.setAttribute( name, value );
+ if (value instanceof HttpSessionBindingListener)
+ ((HttpSessionBindingListener) value).valueBound
+ (new HttpSessionBindingEvent( this, name));
+
}
/**
@@ -228,7 +239,7 @@
* @deprecated
*/
public void removeValue(String name) {
- realSession.removeAttribute(name);
+ removeAttribute(name);
}
/**
@@ -247,16 +258,24 @@
*/
public void removeAttribute(String name) {
checkValid();
+ Object object=realSession.getAttribute( name );
realSession.removeAttribute(name);
+ if (object instanceof HttpSessionBindingListener) {
+ ((HttpSessionBindingListener) object).valueUnbound
+ (new HttpSessionBindingEvent( this, name));
+ }
+
}
public void setMaxInactiveInterval(int interval) {
- realSession.getTimeStamp().setMaxInactiveInterval( interval );
+ realSession.getTimeStamp().setMaxInactiveInterval( interval * 1000 );
}
public int getMaxInactiveInterval() {
checkValid();
- return realSession.getTimeStamp().getMaxInactiveInterval();
+ // We use long because it's better to do /1000 here than
+ // every time the internal code does expire
+ return (int)realSession.getTimeStamp().getMaxInactiveInterval()/1000;
}
// duplicated code, private
1.4 +4 -5 jakarta-tomcat/src/facade22/org/apache/tomcat/facade/Servlet22Manager.java
Index: Servlet22Manager.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/facade22/org/apache/tomcat/facade/Servlet22Manager.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- Servlet22Manager.java 2000/09/24 18:10:55 1.3
+++ Servlet22Manager.java 2000/09/25 06:10:54 1.4
@@ -87,14 +87,13 @@
private Servlet22Manager() {
}
- // XXX XXX XXX The key to open the gate - this is the first attempt,
- // we need a safer mechanism !
- //
- /** The only way to construct a FacadeManager is if you have a valid Context.
+ /** The only way to construct a FacadeManager is if you have a valid
+ * Context.
* XXX make sure Context can't be constructed without right permission.
* ( all internal tomcat objects have to be revisited ).
*
- * The FacadeManager will work only for the Context used at construction time.
+ * The FacadeManager will work only for the Context used at construction
+ * time.
*/
public Servlet22Manager(Context ctx) {
// checkAccess();