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 [EMAIL PROTECTED] * * 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; } }