You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by bi...@apache.org on 2001/04/26 03:36:06 UTC

cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session StoreBase.java

bip         01/04/25 18:36:06

  Added:       catalina/src/share/org/apache/catalina/session
                        StoreBase.java
  Log:
  Moved common code from FileStore/JDBCStore into StoreBase. Extended
  by the concrete Store implementations like FileStore.
  
  Each Store now have the ability to implement their own processExpires()
  and storeStart()/storeStop().
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/StoreBase.java
  
  Index: StoreBase.java
  ===================================================================
  /*
   * StoreBase.java
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session/StoreBase.java,v 1.1 2001/04/26 01:36:05 bip Exp $
   * $Revision: 1.1 $
   * $Date: 2001/04/26 01:36:05 $
   *
   * ====================================================================
   *
   * 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.catalina.session;
  
  import java.beans.PropertyChangeListener;
  import java.beans.PropertyChangeSupport;
  import java.io.IOException;
  import org.apache.catalina.Container;
  import org.apache.catalina.Lifecycle;
  import org.apache.catalina.LifecycleEvent;
  import org.apache.catalina.LifecycleException;
  import org.apache.catalina.LifecycleException;
  import org.apache.catalina.LifecycleListener;
  import org.apache.catalina.Logger;
  import org.apache.catalina.Manager;
  import org.apache.catalina.Store;
  import org.apache.catalina.util.LifecycleSupport;
  import org.apache.catalina.util.StringManager;
  
  /**
   * Abstract implementation of the Store interface to
   * support most of the functionality required by a Store.
   *
   * @author Bip Thelin
   * @version $Revision: 1.1 $, $Date: 2001/04/26 01:36:05 $
   */
  
  public abstract class StoreBase
      implements Lifecycle, Runnable, Store {
  
      // ----------------------------------------------------- Instance Variables
  
      /**
       * The descriptive information about this implementation.
       */
      protected static String info = "StoreBase/1.0";
  
      /**
       * The interval (in seconds) between checks for expired sessions.
       */
      protected int checkInterval = 60;
  
      /**
       * Name to register for the background thread.
       */
      protected String threadName = "StoreBase";
  
      /**
       * Name to register for this Store, used for logging.
       */
      protected static String storeName = "StoreBase";
  
      /**
       * The background thread.
       */
      protected Thread thread = null;
  
      /**
       * The background thread completion semaphore.
       */
      protected boolean threadDone = false;
  
      /**
       * The debugging detail level for this component.
       */
      protected int debug = 0;
  
      /**
       * Has this component been started yet?
       */
      protected boolean started = false;
  
      /**
       * The lifecycle event support for this component.
       */
      protected LifecycleSupport lifecycle = new LifecycleSupport(this);
  
      /**
       * The property change support for this component.
       */
      protected PropertyChangeSupport support = new PropertyChangeSupport(this);
  
      /**
       * The string manager for this package.
       */
      protected StringManager sm = StringManager.getManager(Constants.Package);
  
      /**
       * The Manager with which this JDBCStore is associated.
       */
      protected Manager manager;
  
      // ------------------------------------------------------------- Properties
  
      /**
       * Return the info for this Store.
       */
      public String getInfo() {
  	return(info);
      }
  
      /**
       * Return the thread name for this Store.
       */
      public String getThreadName() {
  	return(threadName);
      }
  
      /**
       * Return the name for this Store, used for logging.
       */
      public String getStoreName() {
  	return(storeName);
      }
  
      /**
       * Set the debugging detail level for this Store.
       *
       * @param debug The new debugging detail level
       */
      public void setDebug(int debug) {
  	this.debug = debug;
      }
  
      /**
       * Return the debugging detail level for this Store.
       */
      public int getDebug() {
  	return(this.debug);
      }
  
  
      /**
       * Set the check interval (in seconds) for this Store.
       *
       * @param checkInterval The new check interval
       */
      public void setCheckInterval(int checkInterval) {
  	int oldCheckInterval = this.checkInterval;
  	this.checkInterval = checkInterval;
  	support.firePropertyChange("checkInterval",
  				   new Integer(oldCheckInterval),
  				   new Integer(this.checkInterval));
      }
  
      /**
       * Return the check interval (in seconds) for this Store.
       */
      public int getCheckInterval() {
  	return(this.checkInterval);
      }
  
      /**
       * Set the Manager with which this Store is associated.
       *
       * @param manager The newly associated Manager
       */
      public void setManager(Manager manager) {
  	Manager oldManager = this.manager;
  	this.manager = manager;
  	support.firePropertyChange("manager", oldManager, this.manager);
      }
  
      /**
       * Return the Manager with which the Store is associated.
       */
      public Manager getManager() {
      	return(this.manager);
      }
  
      // --------------------------------------------------------- Public Methods
  
      /**
       * Add a lifecycle event listener to this component.
       *
       * @param listener The listener to add
       */
      public void addLifecycleListener(LifecycleListener listener) {
  	lifecycle.addLifecycleListener(listener);
      }
  
      /**
       * Remove a lifecycle event listener from this component.
       *
       * @param listener The listener to add
       */
      public void removeLifecycleListener(LifecycleListener listener) {
  	lifecycle.removeLifecycleListener(listener);
      }
  
      /**
       * Add a property change listener to this component.
       *
       * @param listener a value of type 'PropertyChangeListener'
       */
      public void addPropertyChangeListener(PropertyChangeListener listener) {
  	support.addPropertyChangeListener(listener);
      }
  
      /**
       * Remove a property change listener from this component.
       *
       * @param listener The listener to remove
       */
      public void removePropertyChangeListener(PropertyChangeListener listener) {
  	support.removePropertyChangeListener(listener);
      }
  
      // --------------------------------------------------------- Protected Methods
  
      /**
       * Called by our background reaper thread to check if Sessions
       * saved in our store are subject of being expired. If so expire
       * the Session and remove it from the Store.
       *
       */
      protected void processExpires() {
  	long timeNow = System.currentTimeMillis();
  	String[] keys = null;
  
      	if(!started)
      	    return;
  	
  	try {
  	    keys = keys();
  	} catch (IOException e) {
  	    log (e.toString());
  	    e.printStackTrace();
  	    return;
  	}
  	
  	for (int i = 0; i < keys.length; i++) {
  	    try {
  		StandardSession session = (StandardSession) load(keys[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();
  		    remove(session.getId());
  		}
  	    } catch (IOException e) {
  	    	log (e.toString());
  	    	e.printStackTrace();
  	    } catch (ClassNotFoundException e) {
  	    	log (e.toString());
  	    	e.printStackTrace();
  	    }
  	}
      }
  
      /**
       * Log a message on the Logger associated with our Container (if any).
       *
       * @param message Message to be logged
       */
      protected void log(String message) {
  	Logger logger = null;
  	Container container = manager.getContainer();
  
  	if (container != null)
  	    logger = container.getLogger();
  
  	if (logger != null) {
  	    logger.log(getStoreName()+"[" + container.getName() + "]: "
  		       + message);
  	} else {
  	    String containerName = null;
  	    if (container != null)
  		containerName = container.getName();
  	    System.out.println(getStoreName()+"[" + containerName
  			       + "]: " + message);
  	}
      }
  
      /**
       * Called from <b>start()</b> and used for concrete Store
       * implementations that need to add their own <b>start()</b> code.
       *
       */
      protected void storeStart() {
  	;
      }
  
      /**
       * Called from <b>stop()</b> and used for concrete Store
       * implementations that need to add their own <b>stop()</b> code.
       *
       */
      protected void storeStop() {
  	;
      }
  
      // --------------------------------------------------------- Thread Methods
  
      /**
       * The background thread that checks for session timeouts and shutdown.
       */
      public void run() {
  	// Loop until the termination semaphore is set
  	while (!threadDone) {
  	    threadSleep();
  	    processExpires();
  	}
      }
  
      /**
       * 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 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 (started)
  	    throw new LifecycleException
  		(sm.getString(getStoreName()+".alreadyStarted"));
  	lifecycle.fireLifecycleEvent(START_EVENT, null);
  	started = true;
  
  	// Start the background reaper thread
  	threadStart();
  
  	// Start the Store
  	storeStart();
      }
  
      /**
       * 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 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(getStoreName()+".notStarted"));
  	lifecycle.fireLifecycleEvent(STOP_EVENT, null);
  	started = false;
  
  	// Stop the background reaper thread
  	threadStop();
  
  	// Stop the Store.
  	storeStop();
      }
  
      /**
       * Start the background thread that will periodically check for
       * session timeouts.
       */
      protected void threadStart() {
  	if (thread != null)
  	    return;
  
  	threadDone = false;
  	thread = new Thread(this, getThreadName());
  	thread.setDaemon(true);
  	thread.start();
      }
  
      /**
       * Sleep for the duration specified by the <code>checkInterval</code>
       * property.
       */
      protected void threadSleep() {
  	try {
  	    Thread.sleep(checkInterval * 1000L);
  	} catch (InterruptedException e) {
  	    ;
  	}
      }
  
      /**
       * Stop the background thread that is periodically checking for
       * session timeouts.
       */
      protected void threadStop() {
  	if (thread == null)
  	    return;
  
  	threadDone = true;
  	thread.interrupt();
  	try {
  	    thread.join();
  	} catch (InterruptedException e) {
  	    ;
  	}
  
  	thread = null;
      }
  }
  
  
  

Re: cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session StoreBase.java

Posted by cm...@yahoo.com.
> While you are at it, the current convention in Tomcat is to use spaces
> rather than embedded tabs for indentation.  I know some of the old code

Is it a convention or an absolute requirement ? 

Costin
( waiting for the space police to remove my tabs :-)


Re: cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/session StoreBase.java

Posted by "Craig R. McClanahan" <cr...@apache.org>.

On 26 Apr 2001 bip@apache.org wrote:

>
>   Each Store now have the ability to implement their own processExpires()
>   and storeStart()/storeStop().
>   

The typical design pattern for most subclassable components in Catalina is
to have the subclass simply override the methods it needs to, with an
appropriate call to the superclass method.  For example, FileStore would
implement:

  public void start() throws LifecycleException {
    ... stuff before superclass start() is called ...
    super.start();
    ... stuff after superclass start() is called ...
  }

I'd prefer if we used that pattern here as well.

While you are at it, the current convention in Tomcat is to use spaces
rather than embedded tabs for indentation.  I know some of the old code
that you cut and pasted from probably had tabs in it, but new code (and
patches to old code) should use spaces instead.

Craig