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...@apache.org on 2002/01/06 09:34:56 UTC

cvs commit: jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/threads Expirer.java Reaper.java ThreadPool.java ThreadPoolRunnable.java

costin      02/01/06 00:34:56

  Modified:    util/java/org/apache/tomcat/util/http BaseRequest.java
  Added:       util/java/org/apache/tomcat/util/log Log.java
                        LogHandler.java LogManager.java
               util/java/org/apache/tomcat/util/threads Expirer.java
                        Reaper.java ThreadPool.java ThreadPoolRunnable.java
  Log:
  Added 'notes' - to store various information associated with the request.
  ( with fast access time )
  
  Imported the threads from tc. The connector will manage the threads itself,
  it'll be especially important for jni and other channels ( doors maybe ) ( where
  the threads will be created on the C side )
  
  Revision  Changes    Path
  1.4       +11 -1     jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/http/BaseRequest.java
  
  Index: BaseRequest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/http/BaseRequest.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- BaseRequest.java	26 Jun 2001 19:38:12 -0000	1.3
  +++ BaseRequest.java	6 Jan 2002 08:34:56 -0000	1.4
  @@ -58,7 +58,7 @@
   /***************************************************************************
    * Description: Base http request object.                                  *
    * Author:      Keving Seguin [seguin@apache.org]                          *
  - * Version:     $Revision: 1.3 $                                           *
  + * Version:     $Revision: 1.4 $                                           *
    ***************************************************************************/
   
   package org.apache.tomcat.util.http;
  @@ -332,6 +332,16 @@
       // sessions, and on the tomcat side to format the session ids.
       public MessageBytes jvmRoute() {
           return tomcatInstanceId;
  +    }
  +
  +    private Object notes[]=new Object[16];
  +    
  +    public final Object getNote(int id) {
  +        return notes[id];
  +    }
  +
  +    public final void setNote(int id, Object cr) {
  +        notes[id]=cr;
       }
       
       /**
  
  
  
  1.1                  jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/log/Log.java
  
  Index: Log.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/>.
   *
   */ 
  package org.apache.tomcat.util.log;
  
  import java.io.*;
  import java.lang.reflect.*;
  import java.util.*;
  
  
  /**
   * This is the main class seen by objects that need to log. 
   * 
   * It has a log channel to write to; if it can't find a log with that name,
   * it outputs to the default
   * sink.  Also prepends a descriptive name to each message
   * (usually the toString() of the calling object), so it's easier
   * to identify the source.<p>
   *
   * Intended for use by client classes to make it easy to do
   * reliable, consistent logging behavior, even if you don't
   * necessarily have a context, or if you haven't registered any
   * log files yet, or if you're in a non-Tomcat application.
   * <p>
   * Usage: <pre>
   * class Foo {
   *   Log log = Log.getLog("tc_log", "Foo"); // or...
   *   Log log = Log.getLog("tc_log", this); // fills in "Foo" for you
   *   ...
   *     log.log("Something happened");
   *     ...
   *     log.log("Starting something", Log.DEBUG);
   *     ...
   *     catch (IOException e) {
   *       log.log("While doing something", e);
   *     }
   * </pre>
   * 
   *  As a special feature ( required in tomcat operation ) the
   *  Log can be modified at run-time, by changing and configuring the logging
   *  implementation ( without requiring any special change in the user code ).
   *  That means that the  user can do a Log.getLog() at any time,
   *  even before the logging system is fully configured. The
   *  embeding application can then set up or change the logging details,
   *  without any action from the log user.
   *
   * @author Alex Chaffee [alex@jguru.com]
   * @author Costin Manolache
   **/
  public class Log {
  
      /**
       * Verbosity level codes.
       */
      public static final int FATAL = Integer.MIN_VALUE;
      public static final int ERROR = 1;
      public static final int WARNING = 2;
      public static final int INFORMATION = 3;
      public static final int DEBUG = 4;
      
  
      // name of the logger ( each logger has a unique name,
      // used as a key internally )
      protected String logname;
  
      // string displayed at the beginning of each log line,
      // to identify the source
      protected String prefix;
  
      /* The "real" logger. This allows the manager to change the
         sink/logger at runtime, and without requiring the log
         user to do any special action or be aware of the changes
      */
      private LogHandler proxy; // the default
  
      // Used to get access to other logging channels.
      // Can be replaced with an application-specific impl.
      private static LogManager logManager=new LogManager();
  
  
      // -------------------- Various constructors --------------------
  
      protected Log(String channel, String prefix, LogHandler proxy, Object owner) {
  	this.logname=channel;
  	this.prefix=prefix;
  	this.proxy=proxy;
      }
  
      /**
       * @param logname name of log to use
       * @param owner object whose class name to use as prefix
       **/
      public static Log getLog( String channel, String prefix ) {
  	return logManager.getLog( channel, prefix, null );
      }
      
      /**
       * @param logname name of log to use
       * @param prefix string to prepend to each message
       **/
      public static Log getLog( String channel, Object owner ) {
  	return logManager.getLog( channel, null, owner );
      }
      
      // -------------------- Log messages. --------------------
      
      /**
       * Logs the message with level INFORMATION
       **/
      public void log(String msg) 
      {
  	log(msg, null, INFORMATION);
      }
      
      /**
       * Logs the Throwable with level ERROR (assumes an exception is
       * trouble; if it's not, use log(msg, t, level))
       **/
      public void log(String msg, Throwable t) 
      {
  	log(msg, t, ERROR);
      }
      
      /**
       * Logs the message with given level
       **/
      public void log(String msg, int level) 
      {
  	log(msg, null, level);
      }
      
      /**
       * Logs the message and Throwable to its logger or, if logger
       * not found, to the default logger, which writes to the
       * default sink, which is usually System.err
       **/
      public void log(String msg, Throwable t, int level)
      {
  	log( prefix, msg, t, level );
      }
  
      /** 
       */
      public void log( String prefix, String msg, Throwable t, int level ) {
  	proxy.log( prefix, msg, t, level );
      }
      
      /** Flush any buffers.
       *  Override if needed.
       */
      public void flush() {
  	proxy.flush();
      }
  
      public void close() {
  	proxy.close();
      }
  
      /** The configured logging level for this channel
       */
      public int getLevel() {
  	return proxy.getLevel();
      }
  
      // -------------------- Management --------------------
  
      // No getter for the log manager ( user code shouldn't be
      // able to control the logger )
      
      /** Used by the embeding application ( tomcat ) to manage
       *  the logging.
       *
       *  Initially, the Log is not managed, and the default
       *  manager is used. The application can find what loggers
       *  have been created from the default LogManager, and 
       *  provide a special manager implemetation.
       */
      public static LogManager setLogManager( LogManager lm ) {
  	// can be changed only once - so that user
  	// code can't change the log manager in running servers
  	if( logManager.getClass() == LogManager.class ) {
  	    LogManager oldLM=logManager;
  	    logManager=lm;
  	    return oldLM;
  	}
  	return null;
      }
  
      public String  getChannel( LogManager lm ) {
  	if( lm != logManager ) return null;
  	return logname;
      }
  
      public void setProxy( LogManager lm, LogHandler l ) {
  	// only the manager can change the proxy
  	if( lm!= logManager ) {
  	    System.out.println("Attempt to change proxy " + lm + " " + logManager);
  	    return;
  	}
  	proxy=l;
      }
  
      /** Security notes:
  
      Log acts as a facade to an actual logger ( which has setters, etc).
      
      The "manager" ( embeding application ) can set the handler, and
      edit/modify all the properties at run time.
  
      Applications can log if they get a Log instance. From Log there is
      no way to get an instance of the LogHandler or LogManager.
  
      LogManager controls access to the Log channels - a 1.2 implementation
      would check for LogPermissions ( or other mechanisms - like
      information about the current thread, etc ) to determine if the
      code can get a Log.
      
      The "managing application" ( tomcat for example ) can control
      any aspect of the logging and change the actual logging
      implementation behind the scenes.
  
      One typical usage is that various components will use Log.getLog()
      at various moments. The "manager" ( tomcat ) will initialize the
      logging system by setting a LogManager implementation ( which
      can't be changed by user code after that ). It can then set the
      actual implementation of the logger at any time. ( or provide
      access to trusted code to it ).
  
      Please review.
      */
      
      
  }    
  
  
  
  1.1                  jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/log/LogHandler.java
  
  Index: LogHandler.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/>.
   *
   */ 
  package org.apache.tomcat.util.log;
  
  import org.apache.tomcat.util.log.*;
  import java.io.Writer;
  import java.io.PrintWriter;
  import java.io.FileWriter;
  import java.io.File;
  import java.io.OutputStreamWriter;
  import java.io.IOException;
  import java.io.StringWriter;
  
  import java.util.*;
  
  
  /**
   * Log destination ( or channel ). This is the base class that will be
   * extended by log handlers - tomcat uses util.qlog.QueueLogger,
   * in future we'll use log4j or java.util.logger adapters.
   *
   * The base class writes to a (default) writer, and it can
   * be used for very simple logging.
   * 
   * @author Anil Vijendran (akv@eng.sun.com)
   * @author Alex Chaffee (alex@jguru.com)
   * @author Ignacio J. Ortega (nacho@siapi.es)
   * @author Costin Manolache
   */
  public  class LogHandler {
  
      protected PrintWriter sink = defaultSink;
      protected int level = Log.INFORMATION;
  
      
      /**
       * Prints log message and stack trace.
       * This method should be overriden by real logger implementations
       *
       * @param	prefix		optional prefix. 
       * @param	message		the message to log. 
       * @param	t		the exception that was thrown.
       * @param	verbosityLevel	what type of message is this?
       * 				(WARNING/DEBUG/INFO etc)
       */
      public void log(String prefix, String msg, Throwable t,
  		    int verbosityLevel)
      {
  	if( sink==null ) return;
  	// default implementation ( in case no real logging is set up  )
  	if( verbosityLevel > this.level ) return;
  	
  	if (prefix != null) 
  	    sink.println(prefix + ": " + msg );
  	else 
  	    sink.println(  msg );
  	
  	if( t!=null )
  	    t.printStackTrace( sink );
      }
  
      /**
       * Flush the log. 
       */
      public void flush() {
  	if( sink!=null)
  	    sink.flush();
      }
  
  
      /**
       * Close the log. 
       */
      public synchronized void close() {
  	this.sink = null;
      }
      
      /**
       * Set the verbosity level for this logger. This controls how the
       * logs will be filtered. 
       *
       * @param	level		one of the verbosity level codes. 
       */
      public void setLevel(int level) {
  	this.level = level;
      }
      
      /**
       * Get the current verbosity level.
       */
      public int getLevel() {
  	return this.level;
      }
  
  
      // -------------------- Default sink
      
      protected static PrintWriter defaultSink =
  	new PrintWriter( new OutputStreamWriter(System.err));
  
      /**
       * Set the default output stream that is used by all logging
       * channels.
       *
       * @param	w		the default output stream.
       */
      public static void setDefaultSink(Writer w) {
  	if( w instanceof PrintWriter )
  	    defaultSink=(PrintWriter)w;
  	else 
  	    defaultSink = new PrintWriter(w);
      }
  
      // -------------------- General purpose utilitiy --------------------
  
      
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/log/LogManager.java
  
  Index: LogManager.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/>.
   *
   */ 
  package org.apache.tomcat.util.log;
  
  import java.io.*;
  import java.lang.reflect.*;
  import java.util.*;
  
  
  /**
   * Allows the control the log properties at runtime.
   * Normal applications will just use Log, without having to
   * deal with the way the log is configured or managed.
   *
   *
   * @author Alex Chaffee [alex@jguru.com]
   * @author Costin Manolache
   **/
  public class LogManager {
  
      static LogHandler defaultChannel=new LogHandler();
      
      protected Hashtable loggers=new Hashtable();
      protected Hashtable channels=new Hashtable();
  
      public  Hashtable getLoggers() {
  	return loggers;
      }
  
      public Hashtable getChannels() {
  	return channels;
      }
      
      public static void setDefault( LogHandler l ) {
  	if( defaultChannel==null)
  	    defaultChannel=l;
      }
  
      public void addChannel( String name, LogHandler logH ) {
  	if(name==null) name="";
  
  	channels.put( name, logH );
  	Enumeration enum=loggers.keys();
  	while( enum.hasMoreElements() ) {
  	    String k=(String)enum.nextElement();
  	    Log l=(Log)loggers.get( k );
  	    if( name.equals( l.getChannel( this ) )) {
  		l.setProxy( this, logH );
  	    }
  	}
      }
      
      /** Default method to create a log facade.
       */
      public Log getLog( String channel, String prefix,
  		       Object owner ) {
  	if( prefix==null && owner!=null ) {
  	    String cname = owner.getClass().getName();
  	    prefix = cname.substring( cname.lastIndexOf(".") +1);
  	}
  
  	LogHandler proxy=(LogHandler)channels.get(channel);
  	if( proxy==null ) proxy=defaultChannel;
  	
  	// user-level loggers
  	Log log=new Log( channel, prefix, proxy, owner );
  	loggers.put( channel + ":" + prefix, log );
  	if( dL > 0 )
  	    System.out.println("getLog facade " + channel + ":" + prefix);
  	return log;
      }
  
      private static int dL=0;
  
  }    
  
  
  
  1.1                  jakarta-tomcat-connectors/util/java/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.buf.*;
  
  /**
   * 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;
  		managedLen = 2 * managedLen;
  	    }
  	    managedObjs[managedCount]=ts;
  	    managedCount++;
  	}
      }
  
      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-connectors/util/java/org/apache/tomcat/util/threads/Reaper.java
  
  Index: Reaper.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 org.apache.tomcat.util.*;
  
  /**
   * The reaper is a background thread with which ticks every minute
   * and calls registered objects to allow reaping of old session
   * data.
   * 
   * @author James Duncan Davidson [duncan@eng.sun.com]
   * @author Costin Manolache
   */
  public class Reaper extends Thread {
  
      public Reaper() {
  	this.setDaemon(true);
  	this.setName("TomcatReaper");
      }
  
      public Reaper(String name) {
  	this.setDaemon(true);
  	this.setName(name);
      }
  
      private long interval = 1000 * 60; //ms
      
      // XXX TODO Allow per/callback interval, find next, etc
      // Right now the "interval" is used for all callbacks
      // and it represent a sleep between runs.
      
      ThreadPoolRunnable cbacks[]=new ThreadPoolRunnable[30]; // XXX max
      Object tdata[][]=new Object[30][]; // XXX max
      int count=0;
  
      /** Adding and removing callbacks is synchronized
       */
      Object lock=new Object();
      static boolean running=true;
  
      public void setDefaultInterval( long t ) {
  	interval=t;
      }
      
      public int addCallback( ThreadPoolRunnable c, int interval ) {
  	synchronized( lock ) {
  	    cbacks[count]=c;
  	    count++;
  	    return count-1;
  	}
      }
  
      public void removeCallback( int idx ) {
  	synchronized( lock ) {
  	    count--;
  	    cbacks[idx]=cbacks[count];
  	    cbacks[count]=null;
  	}
      }
  
      public void startReaper() {
  	running=true;
  	this.start();
      }
  
      public synchronized void stopReaper() {
  	running=false;
  	System.out.println("Stop reaper ");
  	this.interrupt(); // notify() doesn't stop sleep
      }
      
      public void run() {
  	while (running) {
  	    if( !running) break;
  	    try {
  		this.sleep(interval);
  	    } catch (InterruptedException ie) {
  		// sometimes will happen
  	    }
  
  	    if( !running) break;
  	    for( int i=0; i< count; i++ ) {
  		ThreadPoolRunnable callB=cbacks[i];
  		// it may be null if a callback is removed.
  		//  I think the code is correct
  		if( callB!= null ) {
  		    callB.runIt( tdata[i] );
  		}
  		if( !running) break;
  	    }
  	}
      }
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/threads/ThreadPool.java
  
  Index: ThreadPool.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/threads/ThreadPool.java,v 1.1 2002/01/06 08:34:56 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2002/01/06 08:34:56 $
   *
   * ====================================================================
   *
   * 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.util.zip.*;
  import java.net.*;
  import java.util.*;
  import java.io.*;
  import org.apache.tomcat.util.log.*; 
  
  /**
   * A thread pool that is trying to copy the apache process management.
   *
   * @author Gal Shachor
   */
  public class ThreadPool  {
  
      /*
       * Default values ...
       */
      public static final int MAX_THREADS = 200;
      public static final int MAX_SPARE_THREADS = 50;
      public static final int MIN_SPARE_THREADS = 4;
      public static final int WORK_WAIT_TIMEOUT = 60*1000;
  
      /*
       * Where the threads are held.
       */
      protected Vector pool;
  
      /*
       * A monitor thread that monitors the pool for idel threads.
       */
      protected MonitorRunnable monitor;
  
  
      /*
       * Max number of threads that you can open in the pool.
       */
      protected int maxThreads;
  
      /*
       * Min number of idel threads that you can leave in the pool.
       */
      protected int minSpareThreads;
  
      /*
       * Max number of idel threads that you can leave in the pool.
       */
      protected int maxSpareThreads;
  
      /*
       * Number of threads in the pool.
       */
      protected int currentThreadCount;
  
      /*
       * Number of busy threads in the pool.
       */
      protected int currentThreadsBusy;
  
      /*
       * Flag that the pool should terminate all the threads and stop.
       */
      protected boolean stopThePool;
  
      static int debug=0;
  
      /**
       * Helper object for logging
       **/
      Log loghelper = Log.getLog("tc/ThreadPool", "ThreadPool");
      
      public ThreadPool() {
          maxThreads      = MAX_THREADS;
          maxSpareThreads = MAX_SPARE_THREADS;
          minSpareThreads = MIN_SPARE_THREADS;
          currentThreadCount  = 0;
          currentThreadsBusy  = 0;
          stopThePool = false;
      }
  
      public synchronized void start() {
  	stopThePool=false;
          currentThreadCount  = 0;
          currentThreadsBusy  = 0;
  
          adjustLimits();
  
          openThreads(minSpareThreads);
          monitor = new MonitorRunnable(this);
      }
  
      public void setMaxThreads(int maxThreads) {
          this.maxThreads = maxThreads;
      }
  
      public int getMaxThreads() {
          return maxThreads;
      }
  
      public void setMinSpareThreads(int minSpareThreads) {
          this.minSpareThreads = minSpareThreads;
      }
  
      public int getMinSpareThreads() {
          return minSpareThreads;
      }
  
      public void setMaxSpareThreads(int maxSpareThreads) {
          this.maxSpareThreads = maxSpareThreads;
      }
  
      public int getMaxSpareThreads() {
          return maxSpareThreads;
      }
  
      //
      // You may wonder what you see here ... basically I am trying
      // to maintain a stack of threads. This way locality in time
      // is kept and there is a better chance to find residues of the
      // thread in memory next time it runs.
      //
  
      /**
       * Executes a given Runnable on a thread in the pool, block if needed.
       */
      public void runIt(ThreadPoolRunnable r) {
  
          if(null == r) {
              throw new NullPointerException();
          }
  
          if(0 == currentThreadCount || stopThePool) {
              throw new IllegalStateException();
          }
  
          ControlRunnable c = null;
  
          // Obtain a free thread from the pool.
          synchronized(this) {
              if(currentThreadsBusy == currentThreadCount) {
                   // All threads are busy
                  if(currentThreadCount < maxThreads) {
                      // Not all threads were open,
                      // Open new threads up to the max number of idel threads
                      int toOpen = currentThreadCount + minSpareThreads;
                      openThreads(toOpen);
                  } else {
  		    logFull(loghelper, currentThreadCount, maxThreads);
                      // Wait for a thread to become idel.
                      while(currentThreadsBusy == currentThreadCount) {
                          try {
                              this.wait();
                          }
  			// was just catch Throwable -- but no other
  			// exceptions can be thrown by wait, right?
  			// So we catch and ignore this one, since
  			// it'll never actually happen, since nowhere
  			// do we say pool.interrupt().
  			catch(InterruptedException e) {
  			    loghelper.log("Unexpected exception", e);
                          }
  
                          // Pool was stopped. Get away of the pool.
                          if(0 == currentThreadCount || stopThePool) {
                              throw new IllegalStateException();
                          }
                      }
                  }
              }
  
              // If we are here it means that there is a free thred. Take it.
              c = (ControlRunnable)pool.lastElement();
              pool.removeElement(c);
              currentThreadsBusy++;
          }
          c.runIt(r);
      }
  
      static boolean logfull=true;
      public static void logFull(Log loghelper, int currentThreadCount, int maxThreads) {
  	if( logfull ) {
  	    loghelper.log("All threads are busy, waiting. Please " +
  			  "increase maxThreads or check the servlet" +
  			  " status" + currentThreadCount + " " +
  			  maxThreads  );
  	    logfull=false;
  	} 
      }
  
      /**
       * Stop the thread pool
       */
      public synchronized void shutdown() {
          if(!stopThePool) {
              stopThePool = true;
              monitor.terminate();
              monitor = null;
              for(int i = 0 ; i < (currentThreadCount - currentThreadsBusy) ; i++) {
                  try {
                      ((ControlRunnable)(pool.elementAt(i))).terminate();
                  } catch(Throwable t) {
                      /*
  		     * Do nothing... The show must go on, we are shutting
  		     * down the pool and nothing should stop that.
  		     */
  		    loghelper.log("Ignored exception while shutting down thread pool", t, Log.ERROR);
                  }
              }
              currentThreadsBusy = currentThreadCount = 0;
              pool = null;
              notifyAll();
          }
      }
  
      /**
       * Called by the monitor thread to harvest idle threads.
       */
      protected synchronized void checkSpareControllers() {
  
          if(stopThePool) {
              return;
          }
          if((currentThreadCount - currentThreadsBusy) > maxSpareThreads) {
              int toFree = currentThreadCount -
                           currentThreadsBusy -
                           maxSpareThreads;
  
              for(int i = 0 ; i < toFree ; i++) {
                  ControlRunnable c = (ControlRunnable)pool.firstElement();
                  pool.removeElement(c);
                  c.terminate();
                  currentThreadCount --;
              }
          }
      }
  
      /**
       * Returns the thread to the pool.
       * Called by threads as they are becoming idel.
       */
      protected synchronized void returnController(ControlRunnable c) {
  
          if(0 == currentThreadCount || stopThePool) {
              c.terminate();
              return;
          }
  
          currentThreadsBusy--;
          pool.addElement(c);
          notify();
      }
  
      /**
       * Inform the pool that the specific thread finish.
       *
       * Called by the ControlRunnable.run() when the runnable
       * throws an exception.
       */
      protected synchronized void notifyThreadEnd(ControlRunnable c) {
          currentThreadsBusy--;
          currentThreadCount --;
          notify();
      }
  
  
      /*
       * Checks for problematic configuration and fix it.
       * The fix provides reasonable settings for a single CPU
       * with medium load.
       */
      protected void adjustLimits() {
          if(maxThreads <= 0) {
              maxThreads = MAX_THREADS;
          }
  
          if(maxSpareThreads >= maxThreads) {
              maxSpareThreads = maxThreads;
          }
  
          if(maxSpareThreads <= 0) {
              if(1 == maxThreads) {
                  maxSpareThreads = 1;
              } else {
                  maxSpareThreads = maxThreads/2;
              }
          }
  
          if(minSpareThreads >  maxSpareThreads) {
              minSpareThreads =  maxSpareThreads;
          }
  
          if(minSpareThreads <= 0) {
              if(1 == maxSpareThreads) {
                  minSpareThreads = 1;
              } else {
                  minSpareThreads = maxSpareThreads/2;
              }
          }
      }
  
      protected void openThreads(int toOpen) {
  
          if(toOpen > maxThreads) {
              toOpen = maxThreads;
          }
  
          if(0 == currentThreadCount) {
              pool = new Vector(toOpen);
          }
  
          for(int i = currentThreadCount ; i < toOpen ; i++) {
              pool.addElement(new ControlRunnable(this));
          }
  
          currentThreadCount = toOpen;
      }
  
      void log( String s ) {
  	loghelper.log(s);
  	loghelper.flush();
      }
      
      /** 
       * Periodically execute an action - cleanup in this case
       */
      class MonitorRunnable implements Runnable {
          ThreadPool p;
          Thread     t;
          boolean    shouldTerminate;
  
          MonitorRunnable(ThreadPool p) {
              shouldTerminate = false;
              this.p = p;
              t = new Thread(this);
  	    t.setName( "MonitorRunnable" );
              t.start();
          }
  
          public void run() {
              while(true) {
                  try {
                      // Sleep for a while.
                      synchronized(this) {
                          this.wait(WORK_WAIT_TIMEOUT);
                      }
  
                      // Check if should terminate.
                      // termination happens when the pool is shutting down.
                      if(shouldTerminate) {
                          break;
                      }
  
                      // Harvest idle threads.
                      p.checkSpareControllers();
  
                  } catch(Throwable t) {
  		    loghelper.log("Unexpected exception", t);
  		    loghelper.flush();
                  }
              }
          }
  
  	/** Stop the monitor
  	 */
          public synchronized void terminate() {
              shouldTerminate = true;
              this.notify();
          }
      }
  
      /**
       * A Thread object that executes various actions ( ThreadPoolRunnable )
       *  under control of ThreadPool
       */
      class ControlRunnable implements Runnable {
  
  	/**
  	 * ThreadPool where this thread will be returned
  	 */
          ThreadPool p;
  
  	/**
  	 * The thread that executes the actions
  	 */
          Thread     t;
  
  	/**
  	 * The method that is executed in this thread
  	 */
          ThreadPoolRunnable   toRun;
  
  	/**
  	 * Stop this thread
  	 */
  	boolean    shouldTerminate;
  
  	/**
  	 * Activate the execution of the action
  	 */
          boolean    shouldRun;
  
  	/**
  	 * Per thread data - can be used only if all actions are
  	 *  of the same type.
  	 *  A better mechanism is possible ( that would allow association of
  	 *  thread data with action type ), but right now it's enough.
  	 */
  	boolean noThData;
  	Object thData[]=null;
  
  	/**
  	 * Start a new thread, with no method in it
  	 */
          ControlRunnable(ThreadPool p) {
              toRun = null;
              shouldTerminate = false;
              shouldRun = false;
              this.p = p;
              t = new Thread(this);
              t.start();
  	    noThData=true;
  	    thData=null;
          }
  
          public void run() {
  
              while(true) {
                  try {
  		            /* Wait for work. */
                      synchronized(this) {
                          if(!shouldRun && !shouldTerminate) {
                              this.wait();
                          }
                      }
                      if(toRun == null ) {
                              if( p.debug>0) p.log( "No toRun ???");
                      }
  
                      if( shouldTerminate ) {
                              if( p.debug>0) p.log( "Terminate");
                              break;
                      }
  
                      /* Check if should execute a runnable.  */
                      try {
                          if(noThData) {
                              if(p.debug>0) p.log( "Getting new thread data");
                              thData=toRun.getInitData();
                              noThData = false;
                          }
  
                          if(shouldRun) {
  			    toRun.runIt(thData);
                          }
                      } catch(Throwable t) {
  			loghelper.log("Caught exception executing " + toRun.toString() + ", terminating thread", t);
  			loghelper.flush();
                          /*
                          * The runnable throw an exception (can be even a ThreadDeath),
                          * signalling that the thread die.
                          *
  			* The meaning is that we should release the thread from
  			* the pool.
  			*/
                          shouldTerminate = true;
                          shouldRun = false;
                          p.notifyThreadEnd(this);
                      } finally {
                          if(shouldRun) {
                              shouldRun = false;
                              /*
  			                * Notify the pool that the thread is now idle.
                              */
                              p.returnController(this);
                          }
                      }
  
                      /*
  		     * Check if should terminate.
  		     * termination happens when the pool is shutting down.
  		     */
                      if(shouldTerminate) {
                          break;
                      }
                  } catch(InterruptedException ie) { /* for the wait operation */
  		    // can never happen, since we don't call interrupt
  		    loghelper.log("Unexpected exception", ie);
  		    loghelper.flush();
                  }
              }
          }
  
          public synchronized void runIt(ThreadPoolRunnable toRun) {
  	    if( toRun == null ) {
  		throw new NullPointerException("No Runnable");
  	    }
              this.toRun = toRun;
  	    // Do not re-init, the whole idea is to run init only once per
  	    // thread - the pool is supposed to run a single task, that is
  	    // initialized once.
              // noThData = true;
              shouldRun = true;
              this.notify();
          }
  
          public synchronized void terminate() {
              shouldTerminate = true;
              this.notify();
          }
      }
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/util/java/org/apache/tomcat/util/threads/ThreadPoolRunnable.java
  
  Index: ThreadPoolRunnable.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.util.zip.*;
  import java.net.*;
  import java.util.*;
  import java.io.*;
  
  /** Implemented if you want to run a piece of code inside a thread pool.
   */
  public interface ThreadPoolRunnable {
      // XXX use notes or a hashtable-like
      // Important: ThreadData in JDK1.2 is implemented as a Hashtable( Thread -> object ),
      // expensive.
      
      /** Called when this object is first loaded in the thread pool.
       *  Important: all workers in a pool must be of the same type,
       *  otherwise the mechanism becomes more complex.
       */
      public Object[] getInitData();
  
      /** This method will be executed in one of the pool's threads. The
       *  thread will be returned to the pool.
       */
      public void runIt(Object thData[]);
  
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>