You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by cr...@locus.apache.org on 2000/01/09 04:23:23 UTC

cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/session ManagerBase.java StandardManager.java StandardSession.java StandardSessionManager.java Constants.java LocalStrings.properties

craigmcc    00/01/08 19:23:22

  Modified:    src/share/org/apache/tomcat/session Constants.java
                        LocalStrings.properties
  Added:       src/share/org/apache/tomcat/session ManagerBase.java
                        StandardManager.java StandardSession.java
                        StandardSessionManager.java
  Log:
  Implementation of the Tomcat.Next "Manager" and "Session" interfaces,
  plus an adapter class (StandardSessionManager) that implements the
  interim SessionManager interface that Costin created when refactoring
  the session management stuff.
  
  The new implementation passes all the tests I have run, but needs to be
  tested by others as well.  It will be enabled by the next check-in, a
  one-line patch to org.apache.tomcat.core.Context.
  
  Revision  Changes    Path
  1.2       +2 -0      jakarta-tomcat/src/share/org/apache/tomcat/session/Constants.java
  
  Index: Constants.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/Constants.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Constants.java	2000/01/07 21:11:41	1.1
  +++ Constants.java	2000/01/09 03:23:22	1.2
  @@ -70,4 +70,6 @@
       public static final String Package = "org.apache.tomcat.session";
   
       public static final String SESSION_COOKIE_NAME = "JSESSIONID";
  +    public static final String SESSION_PARAMETER_NAME = "jsessionid";
  +
   }
  
  
  
  1.2       +10 -0     jakarta-tomcat/src/share/org/apache/tomcat/session/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/LocalStrings.properties,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- LocalStrings.properties	2000/01/07 21:11:41	1.1
  +++ LocalStrings.properties	2000/01/09 03:23:22	1.2
  @@ -1,3 +1,13 @@
   applicationSession.session.ise=invalid session state
   applicationSession.value.iae=null value
   serverSession.value.iae=null value
  +standardManager.alreadyConfigured=Manager has already been configured
  +standardManager.alreadyStarted=Manager has already been started
  +standardManager.createSession.ise=createSession: Too many active sessions
  +standardManager.notConfigured=Manager has not yet been configured
  +standardManager.notStarted=Manager has not yet been started
  +standardSession.invalidate.ise=invalidate: Session already invalidated
  +standardSession.isNew.ise=isNew: Session already invalidated
  +standardSession.removeAttribute.ise=removeAttribute: Session already invalidated
  +standardSession.setAttribute.ise=setAttribute: Non-serializable attribute
  +standardSession.setAttribute.ise=setAttribute: Session already invalidated
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/session/ManagerBase.java
  
  Index: ManagerBase.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/ManagerBase.java,v 1.1 2000/01/09 03:23:22 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/01/09 03:23:22 $
   *
   * ====================================================================
   *
   * 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.session;
  
  
  import java.io.IOException;
  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.Container;
  import org.apache.tomcat.Manager;
  import org.apache.tomcat.Request;
  import org.apache.tomcat.Session;
  import org.apache.tomcat.util.SessionUtil;
  
  
  /**
   * Minimal implementation of the <b>Manager</b> interface that supports
   * no session persistence or distributable capabilities.  This class may
   * be subclassed to create more sophisticated Manager implementations.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/01/09 03:23:22 $
   */
  
  public abstract class ManagerBase implements Manager {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The Container with which this Manager is associated.
       */
      protected Container container;
  
  
      /**
       * 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 descriptive information string for this implementation.
       */
      private static final String info = "ManagerBase/1.0";
  
  
      /**
       * The default maximum inactive interval for Sessions created by
       * this Manager.
       */
      protected int maxInactiveInterval = -1;
  
  
      /**
       * The set of previously recycled Sessions for this Manager.
       */
      protected Vector recycled = new Vector();
  
  
      /**
       * The set of currently active Sessions for this Manager, keyed by
       * session identifier.
       */
      protected Hashtable sessions = new Hashtable();
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return the Container with which this Manager is associated.
       */
      public Container getContainer() {
  
  	return (this.container);
  
      }
  
  
      /**
       * Set the Container with which this Manager is associated.
       *
       * @param container The newly associated Container
       */
      public void setContainer(Container container) {
  
  	this.container = container;
  
      }
  
  
      /**
       * Return the distributable flag for the sessions supported by
       * this Manager.
       */
      public boolean getDistributable() {
  
  	return (this.distributable);
  
      }
  
  
      /**
       * 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;
  
      }
  
  
      /**
       * Return descriptive information about this Manager implementation and
       * the corresponding version number, in the format
       * <code>&lt;description&gt;/&lt;version&gt;</code>.
       */
      public String getInfo() {
  
  	return (this.info);
  
      }
  
  
      /**
       * Return the default maximum inactive interval (in seconds)
       * for Sessions created by this Manager.
       */
      public int getMaxInactiveInterval() {
  
  	return (this.maxInactiveInterval);
  
      }
  
  
      /**
       * 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 Methods
  
  
      /**
       * Construct and return a new session object, based on the default
       * settings specified by this Manager's properties.  The session
       * id will be assigned by this method, and available via the getId()
       * method of the returned session.  If a new session cannot be created
       * for any reason, return <code>null</code>.
       *
       * @exception IllegalStateException if a new session cannot be
       *  instantiated for any reason
       */
      public Session createSession() {
  
  	// Recycle or create a Session instance
  	StandardSession session = null;
  	synchronized (recycled) {
  	    int size = recycled.size();
  	    if (size > 0) {
  		session = (StandardSession) recycled.elementAt(size - 1);
  		recycled.removeElementAt(size - 1);
  	    }
  	}
  	if (session == null)
  	    session = new StandardSession(this);
  
  	// Initialize the properties of the new session and return it
  	session.setNew(true);
  	session.setValid(true);
  	session.setCreationTime(System.currentTimeMillis());
  	session.setMaxInactiveInterval(this.maxInactiveInterval);
  	session.setId(SessionUtil.generateSessionId());
  
  	return (session);
  
      }
  
  
      /**
       * Return the active Session, associated with this Manager, with the
       * specified session id (if any); otherwise return <code>null</code>.
       *
       * @param id The session id for the session to be returned
       *
       * @exception ClassNotFoundException if a deserialization error occurs
       *  while processing this request
       * @exception IllegalStateException if a new session cannot be
       *  instantiated for any reason
       * @exception IOException if an input/output error occurs while
       *  processing this request
       */
      public Session findSession(String id) throws IOException {
  
  	if (id == null)
  	    return (null);
  	return ((Session) sessions.get(id));
  
      }
  
  
      /**
       * Return the set of active Sessions associated with this Manager.
       * If this Manager has no active Sessions, a zero-length array is returned.
       */
      public Session[] findSessions() {
  
  	synchronized (sessions) {
  	    Vector keys = new Vector();
  	    Enumeration ids = sessions.keys();
  	    while (ids.hasMoreElements()) {
  		String id = (String) ids.nextElement();
  		keys.addElement(id);
  	    }
  	    Session results[] = new Session[keys.size()];
  	    for (int i = 0; i < results.length; i++) {
  		String key = (String) keys.elementAt(i);
  		results[i] = (Session) sessions.get(key);
  	    }
  	    return (results);
  	}
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Add this Session to the set of active Sessions for this Manager.
       *
       * @param session Session to be added
       */
      void add(StandardSession session) {
  
  	sessions.put(session.getId(), session);
  
      }
  
  
      /**
       * Add this Session to the recycle collection for this Manager.
       *
       * @param session Session to be recycled
       */
      void recycle(StandardSession session) {
  
  	recycled.addElement(session);
  
      }
  
  
      /**
       * Remove this Session from the active Sessions for this Manager.
       *
       * @param session Session to be removed
       */
      void remove(StandardSession session) {
  
  	sessions.remove(session.getId());
  
      }
  
  
  }
  
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/session/StandardManager.java
  
  Index: StandardManager.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/StandardManager.java,v 1.1 2000/01/09 03:23:22 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/01/09 03:23:22 $
   *
   * ====================================================================
   *
   * 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.session;
  
  import java.io.IOException;
  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.Lifecycle;
  import org.apache.tomcat.LifecycleException;
  import org.apache.tomcat.Manager;
  import org.apache.tomcat.Request;
  import org.apache.tomcat.Session;
  import org.apache.tomcat.util.StringManager;
  import org.w3c.dom.NamedNodeMap;
  import org.w3c.dom.Node;
  
  
  /**
   * Standard implementation of the <b>Manager</b> interface that provides
   * no session persistence or distributable capabilities, but does support
   * an optional, configurable, maximum number of active sessions allowed.
   * <p>
   * Lifecycle configuration of this component assumes an XML node
   * in the following format:
   * <code>
   *     &lt;Manager className="org.apache.tomcat.session.StandardManager"
   *              checkInterval="60" maxActiveSessions="-1"
   *              maxInactiveInterval="-1" />
   * </code>
   * where you can adjust the following parameters, with default values
   * in square brackets:
   * <ul>
   * <li><b>checkInterval</b> - The interval (in seconds) between background
   *     thread checks for expired sessions.  [60]
   * <li><b>maxActiveSessions</b> - The maximum number of sessions allowed to
   *     be active at once, or -1 for no limit.  [-1]
   * <li><b>maxInactiveInterval</b> - The default maximum number of seconds of
   *     inactivity before which the servlet container is allowed to time out
   *     a session, or -1 for no limit.  This value should be overridden from
   *     the default session timeout specified in the web application deployment
   *     descriptor, if any.  [-1]
   * </ul>
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/01/09 03:23:22 $
   */
  
  public final class StandardManager
      extends ManagerBase
      implements Lifecycle, Runnable {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The interval (in seconds) between checks for expired sessions.
       */
      private int checkInterval = 60;
  
  
      /**
       * Has this component been configured yet?
       */
      private boolean configured = false;
  
  
      /**
       * The descriptive information about this implementation.
       */
      private static final String info = "StandardManager/1.0";
  
  
      /**
       * The maximum number of active Sessions allowed, or -1 for no limit.
       */
      protected int maxActiveSessions = -1;
  
  
      /**
       * The string manager for this package.
       */
      private StringManager sm =
          StringManager.getManager(Constants.Package);
  
  
      /**
       * Has this component been started yet?
       */
      private boolean started = false;
  
  
      /**
       * The background thread.
       */
      private Thread thread = null;
  
  
      /**
       * The background thread completion semaphore.
       */
      private boolean threadDone = false;
  
  
      /**
       * Name to register for the background thread.
       */
      private String threadName = "StandardManager";
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return the check interval (in seconds) for this Manager.
       */
      public int getCheckInterval() {
  
  	return (this.checkInterval);
  
      }
  
  
      /**
       * Set the check interval (in seconds) for this Manager.
       *
       * @param checkInterval The new check interval
       */
      public void setCheckInterval(int checkInterval) {
  
  	this.checkInterval = checkInterval;
  
      }
  
  
      /**
       * Return descriptive information about this Manager implementation and
       * the corresponding version number, in the format
       * <code>&lt;description&gt;/&lt;version&gt;</code>.
       */
      public String getInfo() {
  
  	return (this.info);
  
      }
  
  
      /**
       * Return the maximum number of active Sessions allowed, or -1 for
       * no limit.
       */
      public int getMaxActiveSessions() {
  
  	return (this.maxActiveSessions);
  
      }
  
  
      /**
       * Set the maximum number of actives Sessions allowed, or -1 for
       * no limit.
       *
       * @param max The new maximum number of sessions
       */
      public void setMaxActiveSessions(int max) {
  
  	this.maxActiveSessions = max;
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Construct and return a new session object, based on the default
       * settings specified by this Manager's properties.  The session
       * id will be assigned by this method, and available via the getId()
       * method of the returned session.  If a new session cannot be created
       * for any reason, return <code>null</code>.
       *
       * @exception IllegalStateException if a new session cannot be
       *  instantiated for any reason
       */
      public Session createSession() {
  
  	if ((maxActiveSessions >= 0) &&
  	  (sessions.size() >= maxActiveSessions))
  	    throw new IllegalStateException
  		(sm.getString("standardManager.createSession.ise"));
  
  	return (super.createSession());
  
      }
  
  
      // ------------------------------------------------------ Lifecycle Methods
  
  
      /**
       * Configure this component, based on the specified configuration
       * parameters.  This method should be called immediately after the
       * component instance is created, and before <code>start()</code>
       * is called.
       *
       * @param parameters Configuration parameters for this component
       *  (<B>FIXME: What object type should this really be?)
       *
       * @exception IllegalStateException if this component has already been
       *  configured and/or started
       * @exception LifecycleException if this component detects a fatal error
       *  in the configuration parameters it was given
       */
      public void configure(Node parameters)
  	throws LifecycleException {
  
  	// Validate and update our current component state
  	if (configured)
  	    throw new LifecycleException
  		(sm.getString("standardManager.alreadyConfigured"));
  	configured = true;
  	if (parameters == null)
  	    return;
  
  	// Parse and process our configuration parameters
  	if (!("Manager".equals(parameters.getNodeName())))
  	    return;
  	NamedNodeMap attributes = parameters.getAttributes();
  	Node node = null;
  
  	node = attributes.getNamedItem("checkInterval");
  	if (node != null) {
  	    try {
  		setCheckInterval(Integer.parseInt(node.getNodeValue()));
  	    } catch (Throwable t) {
  		;	// XXX - Throw exception?
  	    }
  	}
  
  	node = attributes.getNamedItem("maxActiveSessions");
  	if (node != null) {
  	    try {
  		setMaxActiveSessions(Integer.parseInt(node.getNodeValue()));
  	    } catch (Throwable t) {
  		;	// XXX - Throw exception?
  	    }
  	}
  
  	node = attributes.getNamedItem("maxInactiveInterval");
  	if (node != null) {
  	    try {
  		setMaxInactiveInterval(Integer.parseInt(node.getNodeValue()));
  	    } catch (Throwable t) {
  		;	// XXX - Throw exception?
  	    }
  	}
  
      }
  
  
      /**
       * Prepare for the beginning of active use of the public methods of this
       * component.  This method should be called after <code>configure()</code>,
       * and before any of the public methods of the component are utilized.
       *
       * @exception IllegalStateException if this component has not yet been
       *  configured (if required for this component)
       * @exception IllegalStateException if this component has already been
       *  started
       * @exception LifecycleException if this component detects a fatal error
       *  that prevents this component from being used
       */
      public void start() throws LifecycleException {
  
  	// Validate and update our current component state
  	if (!configured)
  	    throw new LifecycleException
  		(sm.getString("standardManager.notConfigured"));
  	if (started)
  	    throw new LifecycleException
  		(sm.getString("standardManager.alreadyStarted"));
  	started = true;
  
  	// Start the background reaper thread
  	threadStart();
  
      }
  
  
      /**
       * Gracefully terminate the active use of the public methods of this
       * component.  This method should be the last one called on a given
       * instance of this component.
       *
       * @exception IllegalStateException if this component has not been started
       * @exception IllegalStateException if this component has already
       *  been stopped
       * @exception LifecycleException if this component detects a fatal error
       *  that needs to be reported
       */
      public void stop() throws LifecycleException {
  
  	// Validate and update our current component state
  	if (!started)
  	    throw new LifecycleException
  		(sm.getString("standardManager.notStarted"));
  	started = false;
  
  	// Stop the background reaper thread
  	threadStop();
  
  	// Expire all active sessions
  	Session sessions[] = findSessions();
  	for (int i = 0; i < sessions.length; i++) {
  	    StandardSession session = (StandardSession) sessions[i];
  	    if (!session.isValid())
  		continue;
  	    session.expire();
  	}
  
      }
  
  
      // -------------------------------------------------------- Private Methods
  
  
      /**
       * Invalidate all sessions that have expired.
       */
      private void processExpires() {
  
  	long timeNow = System.currentTimeMillis();
  	Session sessions[] = findSessions();
  
  	for (int i = 0; i < sessions.length; i++) {
  	    StandardSession session = (StandardSession) sessions[i];
  	    if (!session.isValid())
  		continue;
  	    int maxInactiveInterval = session.getMaxInactiveInterval();
  	    if (maxInactiveInterval < 0)
  		continue;
  	    int timeIdle = // Truncate, do not round up
  		(int) ((timeNow - session.getLastAccessedTime()) / 1000L);
  	    if (timeIdle >= maxInactiveInterval)
  		session.expire();
  	}
      }
  
  
      /**
       * Sleep for the duration specified by the <code>checkInterval</code>
       * property.
       */
      private void threadSleep() {
  
  	try {
  	    Thread.sleep(checkInterval * 1000L);
  	} catch (InterruptedException e) {
  	    ;
  	}
  
      }
  
  
      /**
       * Start the background thread that will periodically check for
       * session timeouts.
       */
      private void threadStart() {
  
  	if (thread != null)
  	    return;
  
  	threadDone = false;
  	thread = new Thread(this, threadName);
  	thread.setDaemon(true);
  	thread.start();
  
      }
  
  
      /**
       * Stop the background thread that is periodically checking for
       * session timeouts.
       */
      private void threadStop() {
  
  	if (thread == null)
  	    return;
  
  	threadDone = true;
  	thread.interrupt();
  	try {
  	    thread.join();
  	} catch (InterruptedException e) {
  	    ;
  	}
  
  	thread = null;
  
      }
  
  
      // ------------------------------------------------------ Background Thread
  
  
      /**
       * The background thread that checks for session timeouts and shutdown.
       */
      public void run() {
  
  	// Loop until the termination semaphore is set
  	while (!threadDone) {
  	    threadSleep();
  	    processExpires();
  	}
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/session/StandardSession.java
  
  Index: StandardSession.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/StandardSession.java,v 1.1 2000/01/09 03:23:22 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/01/09 03:23:22 $
   *
   * ====================================================================
   *
   * 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.session;
  
  
  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;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpSession;
  import javax.servlet.http.HttpSessionBindingEvent;
  import javax.servlet.http.HttpSessionBindingListener;
  import javax.servlet.http.HttpSessionContext;
  import org.apache.tomcat.Manager;
  import org.apache.tomcat.Session;
  import org.apache.tomcat.util.StringManager;
  
  
  /**
   * Standard implementation of the <b>Session</b> interface.  This object is
   * serializable, so that it can be stored in persistent storage or transferred
   * to a different JVM for distributable session support.
   * <p>
   * <b>IMPLEMENTATION NOTE</b>:  An instance of this class represents both the
   * internal (Session) and application level (HttpSession) view of the session.
   * However, because the class itself is not declared public, Java logic outside
   * of the <code>org.apache.tomcat.session</code> package cannot cast an
   * HttpSession view of this instance back to a Session view.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/01/09 03:23:22 $
   */
  
  final class StandardSession
      implements HttpSession, Session {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new Session associated with the specified Manager.
       *
       * @param manager The manager with which this Session is associated
       */
      public StandardSession(Manager manager) {
  
  	super();
  	this.manager = manager;
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The collection of user data attributes associated with this Session.
       */
      private Hashtable attributes = new Hashtable();
  
  
      /**
       * The time this session was created, in milliseconds since midnight,
       * January 1, 1970 GMT.
       */
      private long creationTime = 0L;
  
  
      /**
       * The session identifier of this Session.
       */
      private String id = null;
  
  
      /**
       * Descriptive information describing this Session implementation.
       */
      private static final String info = "StandardSession/1.0";
  
  
      /**
       * The last accessed time for this Session.
       */
      private long lastAccessedTime = creationTime;
  
  
      /**
       * The Manager with which this Session is associated.
       */
      private Manager manager = null;
  
  
      /**
       * The maximum time interval, in seconds, between client requests before
       * the servlet container may invalidate this session.  A negative time
       * indicates that the session should never time out.
       */
      private int maxInactiveInterval = -1;
  
  
      /**
       * Flag indicating whether this session is new or not.
       */
      private boolean isNew = false;
  
  
      /**
       * Flag indicating whether this session is valid or not.
       */
      private boolean isValid = false;
  
  
      /**
       * The string manager for this package.
       */
      private StringManager sm =
          StringManager.getManager(Constants.Package);
  
  
      /**
       * The current accessed time for this session.
       */
      private long thisAccessedTime = creationTime;
  
  
      // ----------------------------------------------------- Session Properties
  
  
      /**
       * Set the creation time for this session.  This method is called by the
       * Manager when an existing Session instance is reused.
       *
       * @param time The new creation time
       */
      public void setCreationTime(long time) {
  
  	this.creationTime = time;
  	this.lastAccessedTime = time;
  	this.thisAccessedTime = time;
  
      }
  
  
      /**
       * Return the session identifier for this session.
       */
      public String getId() {
  
  	return (this.id);
  
      }
  
  
      /**
       * Set the session identifier for this session.
       *
       * @param id The new session identifier
       */
      public void setId(String id) {
  
  	if ((this.id != null) && (manager != null) &&
  	  (manager instanceof ManagerBase))
  	    ((ManagerBase) manager).remove(this);
  
  	this.id = id;
  
  	if ((manager != null) && (manager instanceof ManagerBase))
  	    ((ManagerBase) manager).add(this);
  
      }
  
  
      /**
       * Return descriptive information about this Session implementation and
       * the corresponding version number, in the format
       * <code>&lt;description&gt;/&lt;version&gt;</code>.
       */
      public String getInfo() {
  
  	return (this.info);
  
      }
  
  
      /**
       * Return the last time the client sent a request associated with this
       * session, as the number of milliseconds since midnight, January 1, 1970
       * GMT.  Actions that your application takes, such as getting or setting
       * a value associated with the session, do not affect the access time.
       */
      public long getLastAccessedTime() {
  
  	return (this.lastAccessedTime);
  
      }
  
  
      /**
       * Return the Manager within which this Session is valid.
       */
      public Manager getManager() {
  
  	return (this.manager);
  
      }
  
  
      /**
       * Set the Manager within which this Session is valid.
       *
       * @param manager The new Manager
       */
      public void setManager(Manager manager) {
  
  	this.manager = manager;
  
      }
  
  
      /**
       * Return the maximum time interval, in seconds, between client requests
       * before the servlet container will invalidate the session.  A negative
       * time indicates that the session should never time out.
       */
      public int getMaxInactiveInterval() {
  
  	return (this.maxInactiveInterval);
  
      }
  
  
      /**
       * Set the maximum time interval, in seconds, between client requests
       * before the servlet container will invalidate the session.  A negative
       * time indicates that the session should never time out.
       *
       * @param interval The new maximum interval
       */
      public void setMaxInactiveInterval(int interval) {
  
  	this.maxInactiveInterval = interval;
  
      }
  
  
      /**
       * Return the <code>HttpSession</code> for which this object
       * is the facade.
       */
      public HttpSession getSession() {
  
  	return ((HttpSession) this);
  
      }
  
  
      // ------------------------------------------------- Session Public Methods
  
  
      /**
       * Update the accessed time information for this session.  This method
       * should be called by the context when a request comes in for a particular
       * session, even if the application does not reference it.
       */
      public void access() {
  
  	this.lastAccessedTime = this.thisAccessedTime;
  	this.thisAccessedTime = System.currentTimeMillis();
  
      }
  
  
      /**
       * 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 instanceof ManagerBase))
  	    ((ManagerBase) 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
  	setValid(false);
  
      }
  
  
      /**
       * Release all object references, and initialize instance variables, in
       * preparation for reuse of this object.
       */
      public void recycle() {
  
  	// Reset the instance variables associated with this Session
  	attributes.clear();
  	creationTime = 0L;
  	id = null;
  	lastAccessedTime = 0L;
  	manager = null;
  	maxInactiveInterval = -1;
  	isNew = false;
  	isValid = false;
  
  	// Tell our Manager that this Session has been recycled
  	if ((manager != null) && (manager instanceof ManagerBase))
  	    ((ManagerBase) manager).recycle(this);
  
      }
  
  
      // ------------------------------------------------ Session Package Methods
  
  
      /**
       * Return the <code>isValid</code> flag for this session.
       */
      boolean isValid() {
  
  	return (this.isValid);
  
      }
  
  
      /**
       * Set the <code>isNew</code> flag for this session.
       *
       * @param isNew The new value for the <code>isNew</code> flag
       */
      void setNew(boolean isNew) {
  
  	this.isNew = isNew;
  
      }
  
  
      /**
       * Set the <code>isValid</code> flag for this session.
       *
       * @param isValid The new value for the <code>isValid</code> flag
       */
      void setValid(boolean isValid) {
  
  	this.isValid = isValid;
      }
  
  
      // ------------------------------------------------- HttpSession Properties
  
  
      /**
       * Return the time when this session was created, in milliseconds since
       * midnight, January 1, 1970 GMT.
       */
      public long getCreationTime() {
  
  	return (this.creationTime);
  
      }
  
  
      /**
       * Return the session context with which this session is associated.
       *
       * @deprecated As of Version 2.1, this method is deprecated and has no
       *  replacement.  It will be removed in a future version of the
       *  Java Servlet API.
       */
      public HttpSessionContext getSessionContext() {
  
  	return (null);
  
      }
  
  
      // ----------------------------------------------HttpSession Public Methods
  
  
      /**
       * Return the object bound with the specified name in this session, or
       * <code>null</code> if no object is bound with that name.
       *
       * @param name Name of the attribute to be returned
       */
      public Object getAttribute(String name) {
  
  	return (attributes.get(name));
  
      }
  
  
      /**
       * Return an <code>Enumeration</code> of <code>String</code> objects
       * containing the names of the objects bound to this session.
       */
      public Enumeration getAttributeNames() {
  
  	return (attributes.keys());
  
      }
  
  
      /**
       * Return the object bound with the specified name in this session, or
       * <code>null</code> if no object is bound with that name.
       *
       * @param name Name of the value to be returned
       *
       * @deprecated As of Version 2.2, this method is replaced by
       *  <code>getAttribute()</code>
       */
      public Object getValue(String name) {
  
  	return (getAttribute(name));
  
      }
  
  
      /**
       * Return the set of names of objects bound to this session.  If there
       * are no such objects, a zero-length array is returned.
       *
       * @deprecated As of Version 2.2, this method is replaced by
       *  <code>getAttributeNames()</code>
       */
      public String[] getValueNames() {
  
  	Vector results = new Vector();
  	Enumeration attrs = getAttributeNames();
  	while (attrs.hasMoreElements()) {
  	    String attr = (String) attrs.nextElement();
  	    results.addElement(attr);
  	}
  	String names[] = new String[results.size()];
  	for (int i = 0; i < names.length; i++)
  	    names[i] = (String) results.elementAt(i);
  	return (names);
  
      }
  
  
      /**
       * Invalidates this session and unbinds any objects bound to it.
       *
       * @exception IllegalStateException if this method is called on
       *  an invalidated session
       */
      public void invalidate() {
  
  	if (!isValid())
  	    throw new IllegalStateException
  		(sm.getString("standardSession.invalidate.ise"));
  
  	// Cause this session to expire
  	expire();
  
      }
  
  
      /**
       * Return <code>true</code> if the client does not yet know about the
       * session, or if the client chooses not to join the session.  For
       * example, if the server used only cookie-based sessions, and the client
       * has disabled the use of cookies, then a session would be new on each
       * request.
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       */
      public boolean isNew() {
  
  	if (!isValid())
  	    throw new IllegalStateException
  		(sm.getString("standardSession.isNew.ise"));
  
  	return (this.isNew);
  
      }
  
  
      /**
       * Bind an object to this session, using the specified name.  If an object
       * of the same name is already bound to this session, the object is
       * replaced.
       * <p>
       * After this method executes, and if the object implements
       * <code>HttpSessionBindingListener</code>, the container calls
       * <code>valueBound()</code> on the object.
       *
       * @param name Name to which the object is bound, cannot be null
       * @param value Object to be bound, cannot be null
       *
       * @deprecated As of Version 2.2, this method is replaced by
       *  <code>setAttribute()</code>
       */
      public void putValue(String name, Object value) {
  
  	setAttribute(name, value);
  
      }
  
  
      /**
       * Remove the object bound with the specified name from this session.  If
       * the session does not have an object bound with this name, this method
       * does nothing.
       * <p>
       * After this method executes, and if the object implements
       * <code>HttpSessionBindingListener</code>, the container calls
       * <code>valueUnbound()</code> on the object.
       *
       * @param name Name of the object to remove from this session.
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       */
      public void removeAttribute(String name) {
  
  	if (!isValid())
  	    throw new IllegalStateException
  		(sm.getString("standardSession.removeAttribute.ise"));
  
  	synchronized (attributes) {
  	    Object object = attributes.get(name);
  	    if (object == null)
  		return;
  	    attributes.remove(name);
  	    if (object instanceof HttpSessionBindingListener)
  		((HttpSessionBindingListener) object).valueUnbound
  		    (new HttpSessionBindingEvent((HttpSession) this, name));
  	}
  
      }
  
  
      /**
       * Remove the object bound with the specified name from this session.  If
       * the session does not have an object bound with this name, this method
       * does nothing.
       * <p>
       * After this method executes, and if the object implements
       * <code>HttpSessionBindingListener</code>, the container calls
       * <code>valueUnbound()</code> on the object.
       *
       * @param name Name of the object to remove from this session.
       *
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       *
       * @deprecated As of Version 2.2, this method is replaced by
       *  <code>removeAttribute()</code>
       */
      public void removeValue(String name) {
  
  	removeAttribute(name);
  
      }
  
  
      /**
       * Bind an object to this session, using the specified name.  If an object
       * of the same name is already bound to this session, the object is
       * replaced.
       * <p>
       * After this method executes, and if the object implements
       * <code>HttpSessionBindingListener</code>, the container calls
       * <code>valueBound()</code> on the object.
       *
       * @param name Name to which the object is bound, cannot be null
       * @param value Object to be bound, cannot be null
       *
       * @excpetion IllegalArgumentException if an attempt is made to add a
       *  non-serializable object in an environment marked distributable.
       * @exception IllegalStateException if this method is called on an
       *  invalidated session
       */
      public void setAttribute(String name, Object value) {
  
  	if (!isValid())
  	    throw new IllegalStateException
  		(sm.getString("standardSession.setAttribute.ise"));
  
  	if ((manager != null) && manager.getDistributable() &&
  	  !(value instanceof Serializable))
  	    throw new IllegalArgumentException
  		(sm.getString("standardSession.setAttribute.iae"));
  
  	synchronized (attributes) {
  	    removeAttribute(name);
  	    attributes.put(name, value);
  	    if (value instanceof HttpSessionBindingListener)
  		((HttpSessionBindingListener) value).valueBound
  		    (new HttpSessionBindingEvent((HttpSession) this, name));
  	}
  
      }
  
  
      // -------------------------------------------- HttpSession Private Methods
  
  
      /**
       * Read a serialized version of this session object from the specified
       * object input stream.
       * <p>
       * <b>IMPLEMENTATION NOTE</b>:  The reference to the owning Manager
       * is not restored by this method, and must be set explicitly.
       *
       * @param stream The input stream to read from
       *
       * @exception ClassNotFoundException if an unknown class is specified
       * @exception IOException if an input/output error occurs
       */
      private void readObject(ObjectInputStream stream)
  	throws ClassNotFoundException, IOException {
  
  	// Deserialize the scalar instance variables (except Manager)
  	creationTime = ((Long) stream.readObject()).longValue();
  	id = (String) stream.readObject();
  	lastAccessedTime = ((Long) stream.readObject()).longValue();
  	maxInactiveInterval = ((Integer) stream.readObject()).intValue();
  	isNew = ((Boolean) stream.readObject()).booleanValue();
  	isValid = ((Boolean) stream.readObject()).booleanValue();
  
  	// Deserialize the attribute count and attribute values
  	int n = ((Integer) stream.readObject()).intValue();
  	for (int i = 0; i < n; i++) {
  	    String name = (String) stream.readObject();
  	    Object value = (Object) stream.readObject();
  	    attributes.put(name, value);
  	}
  
      }
  
  
      /**
       * Write a serialized version of this session object to the specified
       * object output stream.
       * <p>
       * <b>IMPLEMENTATION NOTE</b>:  The owning Manager will not be stored
       * in the serialized representation of this Session.  After calling
       * <code>readObject()</code>, you must set the associated Manager
       * explicitly.
       * <p>
       * <b>IMPLEMENTATION NOTE</b>:  Any attribute that is not Serializable
       * will be silently ignored.  If you do not want any such attributes,
       * be sure the <code>distributable</code> property of our associated
       * Manager is set to <code>true</code>.
       *
       * @param stream The output stream to write to
       *
       * @exception IOException if an input/output error occurs
       */
      private void writeObject(ObjectOutputStream stream) throws IOException {
  
  	// Write the scalar instance variables (except Manager)
  	stream.writeObject(new Long(creationTime));
  	stream.writeObject(id);
  	stream.writeObject(new Long(lastAccessedTime));
  	stream.writeObject(new Integer(maxInactiveInterval));
  	stream.writeObject(new Boolean(isNew));
  	stream.writeObject(new Boolean(isValid));
  
  	// Accumulate the names of serializable attributes
  	Vector results = new Vector();
  	Enumeration attrs = getAttributeNames();
  	while (attrs.hasMoreElements()) {
  	    String attr = (String) attrs.nextElement();
  	    Object value = attributes.get(attr);
  	    if (value instanceof Serializable)
  		results.addElement(attr);
  	}
  
  	// Serialize the attribute count and the  attribute values
  	stream.writeObject(new Integer(results.size()));
  	Enumeration names = results.elements();
  	while (names.hasMoreElements()) {
  	    String name = (String) names.nextElement();
  	    stream.writeObject(name);
  	    stream.writeObject(attributes.get(name));
  	}
  
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/session/StandardSessionManager.java
  
  Index: StandardSessionManager.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.session;
  
  import java.io.IOException;
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpSession;
  import org.apache.tomcat.Lifecycle;
  import org.apache.tomcat.LifecycleException;
  import org.apache.tomcat.Manager;
  import org.apache.tomcat.Session;
  import org.apache.tomcat.core.Context;
  import org.apache.tomcat.core.Request;
  import org.apache.tomcat.core.Response;
  import org.apache.tomcat.core.SessionManager;
  import org.apache.tomcat.util.SessionUtil;
  
  
  /**
   * Specialized implementation of org.apache.tomcat.core.SessionManager
   * that adapts to the new component-based Manager implementation.
   * <p>
   * XXX - At present, use of <code>StandardManager</code> is hard coded,
   * and lifecycle configuration is not supported.
   * <p>
   * <b>IMPLEMENTATION NOTE</b>:  Once we commit to the new Manager/Session
   * paradigm, I would suggest moving the logic implemented here back into
   * the core level.  The Tomcat.Next "Manager" interface acts more like a
   * collection class, and has minimal knowledge of the detailed request
   * processing semantics of handling sessions.
   *
   * @author Craig R. McClanahan
   */
  
  public final class StandardSessionManager
      implements SessionManager {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Create a new SessionManager that adapts to the corresponding Manager
       * implementation.
       */
      public StandardSessionManager() {
  
  	manager = new StandardManager();
  	if (manager instanceof Lifecycle) {
  	    try {
  		((Lifecycle) manager).configure(null);
  		((Lifecycle) manager).start();
  	    } catch (LifecycleException e) {
  		throw new IllegalStateException("" + e);
  	    }
  	}
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The Manager implementation we are actually using.
       */
      private Manager manager = null;
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Mark the specified session's last accessed time.  This should be
       * called for each request by a RequestInterceptor.
       *
       * @param session The session to be marked
       */
      public void accessed(HttpSession session) {
  
  	if (session instanceof Session)
  	    ((Session) session).access();
  
      }
  
  
      /**
       * Create a new session object, or get an existing one, associated with
       * the current request.  This method may also be called by
       * RequestInterceptors to find the session that needs to be marked
       * as accessed.  If no such session can be found and create is
       * <code>false</code>, return <code>null</code>.
       *
       * @param request The request being processed
       * @param response The response being created
       * @param create Create the session if necessary
       */
      public HttpSession getSession(Request request, Response response,
  				  boolean create) {
  
  	// Look up the requested session in this request
  	// XXX - Looks at cookies only right now
  	// XXX - Check if request.getRequestedSessionId() returns something
  	//       that might have been set by a connector
  	Cookie cookies[] = request.getCookies();
  	String sessionId = SessionUtil.parseSessionId(cookies);
  	if (sessionId != null)
  	    request.setRequestedSessionId(sessionId);
  	Session session = null;
  	try {
  	    session = manager.findSession(sessionId);
  	} catch (IOException e) {
  	    return (null);
  	}
  
  	// Create a new session if necessary and requested
  	if ((session == null) && create) {
  	    session = manager.createSession();
  	    sessionId = session.getId();
  	    // XXX - Cannot use manager.createCookie() because that would
  	    //       require a Tomcat.Next style Request argument
  	    Cookie cookie = new Cookie
  		(org.apache.tomcat.util.Constants.SESSION.COOKIE_NAME,
  		 sessionId);
  	    // XXX - cookie.setDomain() ???
  	    cookie.setMaxAge(-1);
  	    cookie.setPath("/");	// XXX - request.getContextPath() ???
  	    cookie.setVersion(1);
  	    response.addSystemCookie(cookie);
  	}
  
  	return ((HttpSession) session);
  
      }
  
  
      /**
       * Remove all sessions because our associated Context is being shut down.
       *
       * @param ctx The context that is being shut down
       */
      public void removeSessions(Context ctx) {
  
  	if (manager instanceof Lifecycle) {
  	    try {
  		((Lifecycle) manager).stop();
  	    } catch (LifecycleException e) {
  		throw new IllegalStateException("" + e);
  	    }
  	}
  
      }
  
  
  }