cvs commit: spice/components/threadpool project.xml

[email protected] Wed, 19 Nov 2003 18:23:45 -0600
Newsgroups gmane.comp.java.spice.cvs
Message-ID <[email protected]>
mauro       2003/11/19 18:23:45

  Modified:    components/threadpool/xdocs index.xml
               components/threadpool project.xml
  Added:       components/threadpool/src/java/org/codehaus/spice/threadpool/impl
                        CommonsThreadPool-schema.xml
                        AvalonCommonsThreadPool.xinfo
                        AvalonCommonsThreadPool.java WorkerThread.java
                        AvalonLoggerThreadPoolMonitor.java
                        DefaultThreadControl.java CommonsThreadPool.java
                        DNAThreadPoolMonitor.java DNACommonsThreadPool.java
                        NullThreadPoolMonitor.java AbstractThreadPool.java
                        PicoCommonsThreadPool.java ExecutableRunnable.java
               components/threadpool/src/test/org/codehaus/spice/threadpool/impl
                        DNAThreadPoolTestCase.java Work.java
                        commons-config.xml PicoThreadPoolTestCase.java
                        AvalonThreadPoolTestCase.java ThreadPoolEntry.java
                        AbstractThreadPoolTestCase.java
               components/threadpool/src/java/org/codehaus/spice/threadpool
                        Executable.java ThreadPoolMonitor.java
                        ThreadControl.java ThreadPool.java
  Removed:     components/threadpool/src/java/org/jcomponent/threadpool/impl
                        DNAThreadPoolMonitor.java
                        PicoCommonsThreadPool.java
                        AvalonCommonsThreadPool.java
                        DefaultThreadControl.java WorkerThread.java
                        AvalonLoggerThreadPoolMonitor.java
                        CommonsThreadPool.java ExecutableRunnable.java
                        AbstractThreadPool.java
                        AvalonCommonsThreadPool.xinfo
                        DNACommonsThreadPool.java
                        NullThreadPoolMonitor.java
                        CommonsThreadPool-schema.xml
               components/threadpool/src/test/org/jcomponent/threadpool/impl
                        PicoThreadPoolTestCase.java
                        AvalonThreadPoolTestCase.java commons-config.xml
                        AbstractThreadPoolTestCase.java
                        ThreadPoolEntry.java Work.java
                        DNAThreadPoolTestCase.java
               components/threadpool/src/java/org/jcomponent/threadpool
                        ThreadControl.java ThreadPool.java
                        ThreadPoolMonitor.java Executable.java
  Log:
  Renamed org.jcomponent -> org.codehaus.spice
  
  Revision  Changes    Path
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/CommonsThreadPool-schema.xml
  
  Index: CommonsThreadPool-schema.xml
  ===================================================================
  <?xml version="1.0"?>
  <element
      name="root"
      xmlns="http://relaxng.org/ns/structure/1.0"
      datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
      <interleave>
          <element name="name"><text/></element>
          <element name="priority"><data type="integer"/></element>
          <element name="is-daemon"><data type="boolean"/></element>
          <element name="resource-limiting"><data type="boolean"/></element>
          <element name="max-threads"><data type="integer"/></element>
          <element name="max-idle"><data type="integer"/></element>
      </interleave>
  </element>
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/AvalonCommonsThreadPool.xinfo
  
  Index: AvalonCommonsThreadPool.xinfo
  ===================================================================
  <?xml version="1.0"?>
  <!DOCTYPE blockinfo PUBLIC "-//PHOENIX/Block Info DTD Version 1.0//EN"
                    "http://jakarta.apache.org/avalon/dtds/phoenix/blockinfo_1_0.dtd">
  <blockinfo>
      <block>
          <version>1.0</version>
      </block>
      <services>
          <service name="org.codehaus.spice.threadpool.ThreadPool"/>
      </services>
  </blockinfo>
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/AvalonCommonsThreadPool.java
  
  Index: AvalonCommonsThreadPool.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.apache.avalon.framework.logger.LogEnabled;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.container.ContainerUtil;
  import org.apache.commons.pool.impl.GenericObjectPool;
  
  /**
   * The AvalonCommonsThreadPool wraps the CommonsThreadPool for
   * Avalon-compatible systems.
   * 
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:44 $
   * @phoenix.service type="ThreadPool"
   */
  public class AvalonCommonsThreadPool
      extends CommonsThreadPool
      implements LogEnabled, Configurable, Initializable, Disposable
  {
      /**
       * The logger for component.
       */
      private Logger m_logger;
  
      /**
       * Set the logger for component.
       *
       * @param logger the logger for component.
       */
      public void enableLogging( final Logger logger )
      {
          m_logger = logger;
      }
  
      /**
       * Configure the pool. See class javadocs for example.
       *
       * @param configuration the configuration object
       * @throws ConfigurationException if malformed configuration
       * @phoenix.configuration
       *    type="http://relaxng.org/ns/structure/1.0"
       *    location="CommonsThreadPool-schema.xml"
       */
      public void configure( final Configuration configuration )
          throws ConfigurationException
      {
          final String name =
              configuration.getChild( "name" ).getValue();
          setName( name );
          final int priority =
              configuration.getChild( "priority" ).getValueAsInteger( Thread.NORM_PRIORITY );
          setPriority( priority );
          final boolean isDaemon =
              configuration.getChild( "is-daemon" ).getValueAsBoolean( false );
          setDaemon( isDaemon );
  
          final GenericObjectPool.Config config = getCommonsConfig();
  
          final boolean limit =
              configuration.getChild( "resource-limiting" ).getValueAsBoolean( false );
          if( limit )
          {
              config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK;
          }
          else
          {
              config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
          }
  
          config.maxActive =
              configuration.getChild( "max-threads" ).getValueAsInteger( 10 );
          config.maxIdle = configuration.getChild( "max-idle" ).
              getValueAsInteger( config.maxActive / 2 );
      }
  
      /**
       * Initialize the monitor then initialize parent class.
       */
      public void initialize()
          throws Exception
      {
          final AvalonLoggerThreadPoolMonitor monitor = new AvalonLoggerThreadPoolMonitor();
          ContainerUtil.enableLogging( monitor, m_logger );
          setMonitor( monitor );
          setup();
      }
  
      public void dispose()
      {
          shutdown();
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/WorkerThread.java
  
  Index: WorkerThread.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
  
   * Portions of this software are based upon software originally
   * developed as part of the Apache Avalon project under
   * the Apache 1.1 License.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.codehaus.spice.threadpool.Executable;
  import org.codehaus.spice.threadpool.ThreadControl;
  
  /**
   * This class extends the Thread class to add recyclable functionalities.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:44 $
   */
  public class WorkerThread
      extends Thread
  {
      /**
       * The work currentlyy associated with worker (May be null).
       */
      private Executable m_work;
  
      /**
       * The thread control associated with current work.
       * Should be null if work is null.
       */
      private DefaultThreadControl m_threadControl;
  
      /**
       * True if this thread is alive and not scheduled for shutdown.
       */
      private boolean m_alive;
  
      /**
       * The name of thread.
       */
      private final String m_name;
  
      /**
       * The thread pool this thread is associated with.
       */
      private final AbstractThreadPool m_pool;
  
      /**
       * Allocates a new <code>Worker</code> object.
       */
      protected WorkerThread( final AbstractThreadPool pool,
                              final ThreadGroup group,
                              final String name )
      {
          super( group, "" );
          if( null == name )
          {
              throw new NullPointerException( "name" );
          }
          if( null == pool )
          {
              throw new NullPointerException( "pool" );
          }
          setName( name );
          m_name = name;
          m_work = null;
          m_alive = true;
          m_pool = pool;
  
          setDaemon( false );
      }
  
      /**
       * The main execution loop.
       */
      public final void run()
      {
          debug( "starting." );
  
          // Notify the pool this worker started running.
          //notifyAll();
  
          while( m_alive )
          {
              waitUntilCondition( true );
  
              debug( "running." );
  
              Throwable throwable = null;
              try
              {
                  preExecute();
                  m_work.execute();
              }
              catch( final ThreadDeath threadDeath )
              {
                  debug( "thread has died." );
                  throwable = threadDeath;
                  // This is to let the thread death propagate to the runtime
                  // enviroment to let it know it must kill this worker
                  throw threadDeath;
              }
              catch( final Throwable t )
              {
                  // Error thrown while working.
                  debug( "error caught: " + t );
                  throwable = t;
              }
              finally
              {
                  debug( "done." );
                  m_work = null;
                  m_threadControl.finish( throwable );
                  m_threadControl = null;
                  postExecute();
              }
  
              synchronized( this )
              {
                  //should this be just notify or notifyAll ???
                  //It seems to resource intensive option to use notify()
                  //notifyAll();
                  notifyAll();
              }
  
              // recycle ourselves
              recycleThread();
          }
      }
  
      /**
       * Implement this method to replace thread back into pool.
       */
      protected void recycleThread()
      {
          if( m_alive )
          {
              m_pool.threadCompleted( this );
          }
      }
  
      /**
       * Overide this method to execute something after
       * each bit of "work".
       */
      protected void postExecute()
      {
      }
  
      /**
       * Overide this method to execute something before
       * each bit of "work".
       */
      protected void preExecute()
      {
          //TODO: Thread name setting should reuse the
          //ThreadContext code if ThreadContext used.
          Thread.currentThread().setName( m_name );
      }
  
      /**
       * Set the <tt>alive</tt> variable to false causing the worker to die.
       * If the worker is stalled and a timeout generated this call, this method
       * does not change the state of the worker (that must be destroyed in other
       * ways).
       */
      void dispose( final int maxWait )
      {
          debug( "destroying." );
          m_alive = false;
          interrupt();
          synchronized( this )
          {
              final long start = System.currentTimeMillis();
              while( null != m_work )
              {
                  final long now = System.currentTimeMillis();
                  final long diff = now - start;
                  if( diff >= maxWait )
                  {
                      return;
                  }
                  try
                  {
                      final long timeout = maxWait - diff;
                      debug( "waiting timeout=" + timeout + "." );
                      wait( timeout );
                      debug( "notified." );
                  }
                  catch( final InterruptedException ie )
                  {
                  }
              }
          }
      }
  
      /**
       * Set the <tt>Work</tt> code this <tt>Worker</tt> must
       * execute and <i>notifies</i> its thread to do it.
       */
      protected synchronized ThreadControl execute( final Executable work )
      {
          m_work = work;
          m_threadControl = new DefaultThreadControl( this );
  
          debug( "notifying this worker." );
          notify();
  
          return m_threadControl;
      }
  
      /**
       * Set the <tt>Work</tt> code this <tt>Worker</tt> must
       * execute and <i>notifies</i> its thread to do it. Wait
       * until the executable has finished before returning.
       */
  /*
      protected synchronized void executeAndWait( final Executable work )
      {
          execute( work );
          waitUntilCondition( false );
      }
  */
  
      /**
       * Wait until the worker either has work or doesn't have work.
       *
       * @param hasWork true if waiting till work is present, false otherwise
       */
      private synchronized void waitUntilCondition( final boolean hasWork )
      {
          while( hasWork == ( null == m_work ) )
          {
              try
              {
                  debug( "waiting." );
                  wait();
                  debug( "notified." );
              }
              catch( final InterruptedException ie )
              {
              }
          }
      }
  
      /**
       * Write a debug message.
       * A Noop oin this implementation. Subclasses can overide
       * to actually do some logging.
       *
       * @param message the message to write out
       */
      protected void debug( final String message )
      {
          //System.out.println( getName() + "::" + message );
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/AvalonLoggerThreadPoolMonitor.java
  
  Index: AvalonLoggerThreadPoolMonitor.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.codehaus.spice.threadpool.ThreadPoolMonitor;
  
  /**
   * Implementation of ThreadPoolMonitor which logs event with Avalon logger.
   * 
   * @author <a href="mailto:mauro.talevi at aquilonia.org">Mauro Talevi</a>
   * @author <a href="mailto:paul_hammant at yahoo.com">Paul Hammant</a>
   */
  class AvalonLoggerThreadPoolMonitor
     extends AbstractLogEnabled
     implements ThreadPoolMonitor
  {
     public void newThreadPool( final String name,
                                final int priority,
                                final boolean daemon,
                                final int maxActive,
                                final int maxIdle )
     {
        if ( getLogger().isInfoEnabled() )
        {
           getLogger().info( "Creating a new ThreadPool " + name +
                             "(priority=" + priority +
                             ",isDaemon=" + daemon + ") with " +
                             "max-threads=" + maxActive + " and " +
                             "max-idle=" + maxIdle );
        }
     }
  
     public void threadRetrieved( final Thread thread )
     {
        if ( getLogger().isDebugEnabled() )
        {
           getLogger().debug( "Thread retrieved - " + thread.getName() );
        }
     }
  
     public void threadReturned( final Thread thread )
     {
        if ( getLogger().isDebugEnabled() )
        {
           getLogger().debug( "Thread returned - " + thread.getName() );
        }
     }
  
     public void threadCreated( final Thread thread )
     {
        if ( getLogger().isInfoEnabled() )
        {
           getLogger().info( "Thread Created - " + thread.getName() );
        }
     }
  
     public void threadDisposing( final Thread thread )
     {
        if ( getLogger().isInfoEnabled() )
        {
           getLogger().info( "Thread Disposing - " + thread.getName() );
        }
     }
  
     public void unexpectedError( final String message,
                                      final Throwable t )
     {
        if ( getLogger().isWarnEnabled() )
        {
           getLogger().warn( "Unexpected Error (" + message + ")", t );
        }
     }
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/DefaultThreadControl.java
  
  Index: DefaultThreadControl.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.codehaus.spice.threadpool.ThreadControl;
  
  /**
   * Default implementation of ThreadControl interface.
   * Is used by worker thread to supply control information to the
   * clients of thread pool.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:44 $
   */
  final class DefaultThreadControl
      implements ThreadControl
  {
      ///Thread that this control is associated with
      private Thread m_thread;
  
      ///Throwable that caused thread to terminate
      private Throwable m_throwable;
  
      /**
       * Construct thread control for a specific thread.
       *
       * @param thread the thread to control
       */
      protected DefaultThreadControl( final Thread thread )
      {
          m_thread = thread;
      }
  
      /**
       * Wait for specified time for thread to complete it's work.
       *
       * @param milliSeconds the duration in milliseconds to wait until the thread has finished work
       * @throws IllegalStateException if isValid() == false
       * @throws InterruptedException if another thread has interrupted the current thread.
       *         The interrupted status of the current thread is cleared when this exception
       *         is thrown.
       */
      public synchronized void join( final long milliSeconds )
          throws IllegalStateException, InterruptedException
      {
          final long start = System.currentTimeMillis();
          final long end = start + milliSeconds;
          while( !isFinished() )
          {
              final long now = System.currentTimeMillis();
              if( now >= end )
              {
                  break;
              }
              final long remaining = end - now;
              wait( remaining );
          }
      }
  
      /**
       * Call Thread.interrupt() on thread being controlled.
       *
       * @throws IllegalStateException if isValid() == false
       * @throws SecurityException if caller does not have permission to call interupt()
       */
      public synchronized void interrupt()
          throws IllegalStateException, SecurityException
      {
          if( !isFinished() )
          {
              m_thread.interrupt();
          }
      }
  
      /**
       * Determine if thread has finished execution
       *
       * @return true if thread is finished, false otherwise
       */
      public synchronized boolean isFinished()
      {
          return ( null == m_thread );
      }
  
      /**
       * Retrieve throwable that caused thread to cease execution.
       * Only valid when true == isFinished()
       *
       * @return the throwable that caused thread to finish execution
       */
      public Throwable getThrowable()
      {
          return m_throwable;
      }
  
      /**
       * Method called by thread to release control.
       *
       * @param throwable Throwable that caused thread to complete (may be null)
       */
      protected synchronized void finish( final Throwable throwable )
      {
          m_thread = null;
          m_throwable = throwable;
          notifyAll();
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/CommonsThreadPool.java
  
  Index: CommonsThreadPool.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.apache.commons.pool.PoolableObjectFactory;
  import org.apache.commons.pool.impl.GenericObjectPool;
  import org.codehaus.spice.threadpool.ThreadPool;
  import org.codehaus.spice.threadpool.ThreadPoolMonitor;
  
  /**
   * The CommonsThreadPool is a component that provides a basic
   * mechanism for pooling threads. A sample configuration for this
   * component is;
   * <pre>
   * &lt;config&gt;
   *   &lt;name&gt;MyThreadPool&lt;/name&gt; &lt;!-- base name of all threads --&gt;
   *   &lt;priority&gt;5&lt;/priority&gt; &lt;!-- set to default priority --&gt;
   *   &lt;is-daemon&gt;false&lt;/is-daemon&gt; &lt;!-- are threads daemon threads? --&gt;
   *   &lt;resource-limiting&gt;false&lt;/resource-limiting&gt; &lt;!-- will pool block when max threads reached? --&gt;
   *   &lt;max-threads&gt;10&lt;/max-threads&gt;
   *   &lt;max-idle&gt;5&lt;/max-idle&gt; &lt;!-- maximum number of idle threads --&gt;
   * &lt;/config&gt;
   * </pre>
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:44 $
   */
  public class CommonsThreadPool
      extends AbstractThreadPool
      implements ThreadPool, PoolableObjectFactory
  {
      /**
       * The configuration 'struct' for our object pool.
       */
      private final GenericObjectPool.Config m_config = new GenericObjectPool.Config();
  
      /**
       * The underlying pool used to pool threads.
       */
      private GenericObjectPool m_pool;
  
     /**
       * Flag indicating whether component is disposed.
       * If it is disposed it should not try to repool workers.
       */
      private boolean m_disposed;
  
      /**
       * The monitor that receives notifications of
       * changes in pool.
       */
      private ThreadPoolMonitor m_monitor;
  
     /**
       * Initialize the underlying pool.
       */
      public void setup()
      {
          setThreadGroup( Thread.currentThread().getThreadGroup() );
          m_monitor.newThreadPool( getName(),
                                   getPriority(),
                                   isDaemon(),
                                   m_config.maxActive,
                                   m_config.maxIdle );
          m_pool = new GenericObjectPool( this, m_config );
          setDisposeTime( 100 );
      }
  
      /**
       * Shutdown all threads associated with pool.
       */
      public void shutdown()
      {
          shutdownInUseThreads();
          m_disposed = true;
          try
          {
              m_pool.close();
          }
          catch( final Exception e )
          {
              final String message = "Error closing pool: " + e;
              m_monitor.unexpectedError( message, e );
          }
      }
  
      /**
       * Retrieve a worker thread from pool.
       *
       * @return the worker thread retrieved from pool
       */
      protected WorkerThread getWorker()
      {
          try
          {
              final WorkerThread worker = (WorkerThread)m_pool.borrowObject();
              m_monitor.threadRetrieved( worker );
              return worker;
          }
          catch( final Exception e )
          {
              m_monitor.unexpectedError( "Retrieving thread from pool", e );
              return createWorker();
          }
      }
  
      /**
       * Return the WorkerThread to the pool.
       *
       * @param worker the worker thread to put back in pool
       */
      protected void releaseWorker( final WorkerThread worker )
      {
          if( m_disposed )
          {
              final String message =
                 "Ignoring attempt to return worker to " +
                 "disposed pool: " + worker.getName() +
                 ". Attempting dispose of worker.";
              m_monitor.unexpectedError( message, null );
              destroyWorker( worker );
              return;
          }
  
          m_monitor.threadReturned( worker );
          try
          {
              m_pool.returnObject( worker );
          }
          catch( final Exception e )
          {
             final String message =
                "Returning '" + worker.getName() + "' To Pool";
              m_monitor.unexpectedError( message, e );
          }
      }
  
      /**
       * Overide creation of worker to add logging.
       *
       * @return the new worker thread
       */
      protected WorkerThread createWorker()
      {
          final WorkerThread worker = super.createWorker();
          m_monitor.threadCreated( worker );
          return worker;
      }
  
      /**
       * Overide destruction of worker to add logging.
       *
       * @param worker the worker thread
       */
      protected void destroyWorker( final WorkerThread worker )
      {
          m_monitor.threadDisposing( worker );
          super.destroyWorker( worker );
      }
  
      /**
       * Create a new worker. (Part of {@link PoolableObjectFactory} interface)
       *
       * @return the new worker
       */
      public Object makeObject()
      {
          return createWorker();
      }
  
      /**
       * Destroy a worker. (Part of {@link PoolableObjectFactory} interface)
       *
       * @param worker the new worker
       */
      public void destroyObject( final Object worker )
      {
          destroyWorker( (WorkerThread)worker );
      }
  
      /**
       * validate a worker. (Part of {@link PoolableObjectFactory} interface)
       *
       * @return true (no validation occurs)
       */
      public boolean validateObject( final Object worker )
      {
          return true;
      }
  
      /**
       * activate a worker. (Part of {@link PoolableObjectFactory} interface)
       * No-op.
       */
      public void activateObject( final Object worker )
      {
      }
  
      /**
       * passivate a worker. (Part of {@link PoolableObjectFactory} interface)
       * No-op.
       */
      public void passivateObject( final Object worker )
      {
      }
  
      /**
       * Return the configuration object for Commons Pool.
       *
       * @return the configuration object for Commons Pool.
       */
      protected final GenericObjectPool.Config getCommonsConfig()
      {
          return m_config;
      }
  
      /**
       * Set the Monitor to use to notify of changes in the Pool.
       *
       * @param monitor the Monitor to use to notify of changes in the Pool.
       */
      protected final void setMonitor( final ThreadPoolMonitor monitor )
      {
          m_monitor = monitor;
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/DNAThreadPoolMonitor.java
  
  Index: DNAThreadPoolMonitor.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.jcontainer.dna.AbstractLogEnabled;
  import org.codehaus.spice.threadpool.ThreadPoolMonitor;
  
  /**
   * Implementation of ThreadPoolMonitor which logs event with DNA logger.
   * 
   * @author <a href="mailto:mauro.talevi at aquilonia.org">Mauro Talevi</a>
   */
  class DNAThreadPoolMonitor
     extends AbstractLogEnabled
     implements ThreadPoolMonitor
  {
     public void newThreadPool( final String name,
                                final int priority,
                                final boolean daemon,
                                final int maxActive,
                                final int maxIdle )
     {
        if ( getLogger().isInfoEnabled() )
        {
           getLogger().info( "Creating a new ThreadPool " + name +
                             "(priority=" + priority +
                             ",isDaemon=" + daemon + ") with " +
                             "max-threads=" + maxActive + " and " +
                             "max-idle=" + maxIdle );
        }
     }
  
     public void threadRetrieved( final Thread thread )
     {
        if ( getLogger().isDebugEnabled() )
        {
           getLogger().debug( "Thread retrieved - " + thread.getName() );
        }
     }
  
     public void threadReturned( final Thread thread )
     {
        if ( getLogger().isDebugEnabled() )
        {
           getLogger().debug( "Thread returned - " + thread.getName() );
        }
     }
  
     public void threadCreated( final Thread thread )
     {
        if ( getLogger().isInfoEnabled() )
        {
           getLogger().info( "Thread Created - " + thread.getName() );
        }
     }
  
     public void threadDisposing( final Thread thread )
     {
        if ( getLogger().isInfoEnabled() )
        {
           getLogger().info( "Thread Disposing - " + thread.getName() );
        }
     }
  
     public void unexpectedError( final String message,
                                      final Throwable t )
     {
        if ( getLogger().isWarnEnabled() )
        {
           getLogger().warn( "Unexpected Error (" + message + ")", t );
        }
     }
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/DNACommonsThreadPool.java
  
  Index: DNACommonsThreadPool.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.apache.commons.pool.impl.GenericObjectPool;
  import org.jcontainer.dna.Active;
  import org.jcontainer.dna.Configurable;
  import org.jcontainer.dna.Configuration;
  import org.jcontainer.dna.ConfigurationException;
  import org.jcontainer.dna.LogEnabled;
  import org.jcontainer.dna.Logger;
  import org.jcontainer.dna.impl.ContainerUtil;
  
  /**
   * The DNACommonsThreadPool wraps the CommonsThreadPool for
   * DNA-compatible systems.
   *
   * @author <a href="mailto:mauro.talevi at aquilonia.org">Mauro Talevi</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:44 $
   * @dna.service type="ThreadPool"
   */
  public class DNACommonsThreadPool
      extends CommonsThreadPool
      implements LogEnabled, Configurable, Active
  {
      /**
       * The logger for component.
       */
      private Logger m_logger;
  
      /**
       * Set the logger for component.
       *
       * @param logger the logger for component.
       */
      public void enableLogging( final Logger logger )
      {
          m_logger = logger;
      }
  
      /**
       * Configure the pool. See class javadocs for example.
       *
       * @param configuration the configuration object
       * @throws ConfigurationException if malformed configuration
       * @dna.configuration
       *    type="http://relaxng.org/ns/structure/1.0"
       *    location="CommonsThreadPool-schema.xml"
       */
      public void configure( final Configuration configuration )
          throws ConfigurationException
      {
          final String name =
              configuration.getChild( "name" ).getValue();
          setName( name );
          final int priority =
              configuration.getChild( "priority" ).getValueAsInteger( Thread.NORM_PRIORITY );
          setPriority( priority );
          final boolean isDaemon =
              configuration.getChild( "is-daemon" ).getValueAsBoolean( false );
          setDaemon( isDaemon );
  
          final GenericObjectPool.Config config = getCommonsConfig();
  
          final boolean limit =
              configuration.getChild( "resource-limiting" ).getValueAsBoolean( false );
          if( limit )
          {
              config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK;
          }
          else
          {
              config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
          }
  
          config.maxActive =
              configuration.getChild( "max-threads" ).getValueAsInteger( 10 );
          config.maxIdle = configuration.getChild( "max-idle" ).
              getValueAsInteger( config.maxActive / 2 );
      }
  
      /**
       * Initialize the monitor then initialize parent class.
       */
      public void initialize()
          throws Exception
      {
          final DNAThreadPoolMonitor monitor = new DNAThreadPoolMonitor();
          ContainerUtil.enableLogging( monitor, m_logger );
          setMonitor( monitor );
          setup();
      }
  
      public void dispose()
      {
          shutdown();
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/NullThreadPoolMonitor.java
  
  Index: NullThreadPoolMonitor.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
   package org.codehaus.spice.threadpool.impl;
  
  import org.codehaus.spice.threadpool.ThreadPoolMonitor;
  
  /**
   * No-op implementation of ThreadPoolMonitor.
   * 
   * @author <a href="mailto:mauro.talevi at aquilonia.org">Mauro Talevi</a>
   * @author <a href="mailto:paul_hammant at yahoo.com">Paul Hammant</a>
   */
  class NullThreadPoolMonitor
     implements ThreadPoolMonitor
  {
     public void newThreadPool( final String name,
                                final int priority,
                                final boolean daemon,
                                final int maxActive,
                                final int maxIdle )
     {
     }
  
     public void threadRetrieved( final Thread thread )
     {
     }
  
     public void threadReturned( final Thread thread )
     {
     }
  
     public void threadCreated( final Thread thread )
     {
     }
  
     public void threadDisposing( final Thread thread )
     {
     }
  
     public void unexpectedError( final String message,
                                  final Throwable t )
     {
     }
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/AbstractThreadPool.java
  
  Index: AbstractThreadPool.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.codehaus.spice.threadpool.ThreadPool;
  import org.codehaus.spice.threadpool.ThreadControl;
  import org.codehaus.spice.threadpool.Executable;
  import java.util.Set;
  import java.util.HashSet;
  import java.util.Collections;
  import java.util.Iterator;
  
  /**
   * This is the base class of all ThreadPools.
   * Sub-classes should implement the abstract methods to
   * retrieve and return Threads to the pool.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:44 $
   * @phoenix.service type="ThreadPool"
   */
  public abstract class AbstractThreadPool
      implements ThreadPool
  {
      /**
       * The set of threads that are currently in use.
       */
      private Set m_inUse = Collections.synchronizedSet( new HashSet() );
  
      /**
       * The thread group associated with pool.
       */
      private ThreadGroup m_threadGroup;
  
      /**
       * The name of the thread pool.
       * Used in naming threads.
       */
      private String m_name;
  
      /**
       * A Running number that indicates the number
       * of threads created by pool. Starts at 0 and
       * increases.
       */
      private int m_level;
  
      /**
       * A falg indicating whether the pool should create daemon threads.
       */
      private boolean m_isDaemon;
  
      /**
       * The priorty of the threads created by pool.
       */
      private int m_priority;
  
      /**
       * The maximum amount of time that will be spent disposing a thread.
       */
      private int m_disposeTime = 100;
  
      /**
       * Destroy a worker thread by scheduling it for shutdown.
       *
       * @param worker the worker thread
       */
      protected void destroyWorker( final WorkerThread worker )
      {
          worker.dispose( getDisposeTime() );
      }
  
      /**
       * Create a WorkerThread and start it up.
       *
       * @return the worker thread.
       */
      protected WorkerThread createWorker()
      {
          final String name = getName() + " Worker #" + m_level++;
  
          final WorkerThread worker = newWorkerThread( name );
          worker.setDaemon( m_isDaemon );
          worker.setPriority( m_priority );
          worker.start();
          return worker;
      }
  
      /**
       * Create a new worker for pool.
       *
       * @param name the name of worker
       * @return the new WorkerThread
       */
      protected WorkerThread newWorkerThread( final String name )
      {
          return new WorkerThread( this, getThreadGroup(), name );
      }
  
      /**
       * Run work in separate thread.
       * Return a valid ThreadControl to control work thread.
       *
       * @param work the work to be executed.
       * @return the ThreadControl
       */
      public ThreadControl execute( final Runnable work )
      {
          return execute( new ExecutableRunnable( work ) );
      }
  
      /**
       * Execute some executable work in a thread.
       *
       * @param work the work
       * @return the ThreadControl
       */
      public ThreadControl execute( final Executable work )
      {
          final WorkerThread worker = getWorker();
          worker.setPriority( m_priority );
          m_inUse.add( worker );
          return worker.execute( work );
      }
  
      /**
       * Helper method that attempts to shutdown all
       * threads that originated from this pool and are
       * currently in use.
       */
      protected void shutdownInUseThreads()
      {
          synchronized( m_inUse )
          {
              final Iterator iterator = m_inUse.iterator();
              while( iterator.hasNext() )
              {
                  final WorkerThread worker = (WorkerThread)iterator.next();
                  destroyWorker( worker );
              }
              m_inUse.clear();
          }
      }
  
      /**
       * Get the name used for thread pool.
       * (Used in naming threads).
       *
       * @return the thread pool name
       */
      protected String getName()
      {
          return m_name;
      }
  
      /**
       * Set the name used for thread pool.
       * Used in naming threads.
       *
       * @param name the thread pool name
       */
      protected void setName( final String name )
      {
          m_name = name;
      }
  
      /**
       * Set flag indicating whether daemon threads should be created by pool.
       *
       * @param daemon flag indicating whether daemon threads should be created by pool.
       */
      protected void setDaemon( final boolean daemon )
      {
          m_isDaemon = daemon;
      }
  
      /**
       * Return flag indicating whether daemon threads should be created by pool.
       *
       * @return flag indicating whether daemon threads should be created by pool.
       */
      protected boolean isDaemon()
      {
          return m_isDaemon;
      }
  
      /**
       * Set the priorty of threads created for pool.
       *
       * @param priority the priorty of threads created for pool.
       */
      protected void setPriority( int priority )
      {
          m_priority = priority;
      }
  
      /**
       * Return the priorty of threads created for pool.
       *
       * @return the priorty of threads created for pool.
       */
      protected int getPriority()
      {
          return m_priority;
      }
  
      /**
       * Return the thread group that thread pool is associated with.
       *
       * @return the thread group that thread pool is associated with.
       */
      protected ThreadGroup getThreadGroup()
      {
          return m_threadGroup;
      }
  
      /**
       * Set the thread group that thread pool is associated with.
       *
       * @param threadGroup the thread group that thread pool is associated with.
       */
      protected void setThreadGroup( final ThreadGroup threadGroup )
      {
          m_threadGroup = threadGroup;
      }
  
      /**
       * Return the maximum amount of time that will be spent disposing a thread.
       *
       * @return the maximum amount of time that will be spent disposing a thread.
       */
      protected int getDisposeTime()
      {
          return m_disposeTime;
      }
  
      /**
       * Set the maximum amount of time that will be spent disposing a thread.
       *
       * @param disposeTime the maximum amount of time that will be spent disposing a thread.
       */
      protected void setDisposeTime( final int disposeTime )
      {
          m_disposeTime = disposeTime;
      }
  
      /**
       * Return the WorkerThread to management by the ThreadPool object.
       *
       * @param worker the worker
       */
      protected void threadCompleted( final WorkerThread worker )
      {
          m_inUse.remove( worker );
          releaseWorker( worker );
      }
  
      /**
       * Retrieve a worker thread from pool.
       *
       * @return the worker thread retrieved from pool
       */
      protected abstract WorkerThread getWorker();
  
      /**
       * Return the WorkerThread to the pool.
       *
       * @param worker the worker thread to put back in pool
       */
      protected abstract void releaseWorker( WorkerThread worker );
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/PicoCommonsThreadPool.java
  
  Index: PicoCommonsThreadPool.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.apache.commons.pool.impl.GenericObjectPool;
  import org.codehaus.spice.threadpool.ThreadPoolMonitor;
  
  /**
   * The PicoCommonsThreadPool wraps the CommonsThreadPool for
   * Pico-compatible systems.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:44 $
   */
  public class PicoCommonsThreadPool
      extends CommonsThreadPool
  {
      public static class Default
          extends PicoCommonsThreadPool
      {
          public Default()
          {
              super( new NullThreadPoolMonitor(),
                     "Default ThreadPool",
                     Thread.NORM_PRIORITY,
                     false,
                     false,
                     10,
                     5 );
          }
      }
  
      public static class WithMonitor
          extends PicoCommonsThreadPool
      {
          public WithMonitor( final ThreadPoolMonitor monitor )
          {
              super( monitor,
                     "Default ThreadPool",
                     Thread.NORM_PRIORITY,
                     false,
                     false,
                     10,
                     5 );
          }
      }
  
      public static class WithMonitorAndConfig
          extends PicoCommonsThreadPool
      {
          public WithMonitorAndConfig( final ThreadPoolMonitor monitor,
                                       final String name,
                                       final int priority,
                                       final boolean isDaemon,
                                       final boolean limited,
                                       final int maxActiveThreads,
                                       final int maxIdleThreads )
          {
              super( monitor, name, priority, isDaemon, limited, maxActiveThreads, maxIdleThreads );
          }
      }
  
      /**
       * Constructor
       *
       */
      protected PicoCommonsThreadPool( final ThreadPoolMonitor monitor,
                                       final String name,
                                       final int priority,
                                       final boolean isDaemon,
                                       final boolean limited,
                                       final int maxActiveThreads,
                                       final int maxIdleThreads )
      {
          setMonitor( monitor );
          setName( name );
          setPriority( priority );
          setDaemon( isDaemon );
  
          final GenericObjectPool.Config config = getCommonsConfig();
          if( limited )
          {
              config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK;
          }
          else
          {
              config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
          }
  
          config.maxActive = maxActiveThreads;
          config.maxIdle = maxIdleThreads;
          setup();
      }
  
      /**
       * Make sure that finalize results in disposal
       * of the system.
       */
      protected void finalize()
      {
          shutdown();
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/impl/ExecutableRunnable.java
  
  Index: ExecutableRunnable.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.codehaus.spice.threadpool.Executable;
  
  /**
   * Class to adapt a {@link Runnable} object in
   * an {@link Executable} object.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:44 $
   */
  final class ExecutableRunnable
      implements Executable
  {
      ///The runnable instance being wrapped
      private Runnable m_runnable;
  
      /**
       * Create adapter using specified runnable.
       *
       * @param runnable the runnable to adapt to
       */
      protected ExecutableRunnable( final Runnable runnable )
      {
          if( null == runnable )
          {
              throw new NullPointerException( "runnable" );
          }
          m_runnable = runnable;
      }
  
      /**
       * Execute the underlying {@link Runnable} object.
       *
       * @throws Exception if an error occurs
       */
      public void execute()
          throws Exception
      {
          m_runnable.run();
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/test/org/codehaus/spice/threadpool/impl/DNAThreadPoolTestCase.java
  
  Index: DNAThreadPoolTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.codehaus.spice.threadpool.ThreadPool;
  import org.jcontainer.dna.impl.ConsoleLogger;
  import org.jcontainer.dna.impl.ContainerUtil;
  import org.jcontainer.dna.impl.DefaultConfiguration;
  
  /**
   *  A TestCase for the DNACommonsThreadPool.
   *
   * @author <a href="mailto:mauro.talevi at aquilonia.org">Mauro Talevi</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:45 $
   */
  public class DNAThreadPoolTestCase
      extends AbstractThreadPoolTestCase
  {
      public DNAThreadPoolTestCase( final String name )
      {
          super( name );
      }
  
      protected AbstractThreadPool createThreadPool() throws Exception
      {
          return createDNAThreadPool( ConsoleLogger.LEVEL_NONE);
      }
  
      protected AbstractThreadPool createThreadPoolWithDebug() throws Exception
      {
          return createDNAThreadPool( ConsoleLogger.LEVEL_DEBUG );
      }
  
      protected void destroyThreadPool( final ThreadPool threadPool ) throws Exception
      {
          ContainerUtil.dispose( threadPool );
      }
  
      private DNACommonsThreadPool createDNAThreadPool( final int debug ) throws Exception
      {
          final DNACommonsThreadPool threadPool = new DNACommonsThreadPool();
          ContainerUtil.enableLogging( threadPool, new ConsoleLogger( debug ) );
          DefaultConfiguration configuration = buildConfiguration();
          ContainerUtil.configure( threadPool, configuration );
          ContainerUtil.initialize( threadPool );
          return threadPool;
      }
  
      private DefaultConfiguration buildConfiguration()
      {
          final DefaultConfiguration configuration = new DefaultConfiguration( "root", "", "" );
          addChild( configuration, "name", "testThreadPool" );
          addChild( configuration, "priority", "5" );
          addChild( configuration, "is-daemon", "false" );
          addChild( configuration, "max-threads", "3" );
          addChild( configuration, "max-idle", "1" );
          return configuration;
      }
  
      private void addChild( final DefaultConfiguration configuration,
                             final String name,
                             final String value )
      {
          final DefaultConfiguration child = new DefaultConfiguration( name, "", "" );
          child.setValue( value );
          configuration.addChild( child );
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/test/org/codehaus/spice/threadpool/impl/Work.java
  
  Index: Work.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.codehaus.spice.threadpool.Executable;
  
  /**
   * A bit of work used during testing.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:45 $
   */
  class Work
      implements Runnable, Executable
  {
      private boolean m_locked;
      private int m_sleep;
      private final Throwable m_exception;
      private boolean m_interupted;
      private boolean m_done;
  
      public Work( boolean locked, int sleep, Throwable exception )
      {
          m_locked = locked;
          m_sleep = sleep;
          m_exception = exception;
      }
  
      public void run()
      {
          try
          {
              doWork();
          }
          finally
          {
              m_done = true;
          }
      }
  
      public void execute()
          throws Exception
      {
          try
          {
              doWork();
              if( null != m_exception )
              {
                  m_exception.fillInStackTrace();
                  if( m_exception instanceof Exception )
                  {
                      throw (Exception)m_exception;
                  }
                  else
                  {
                      throw (Error)m_exception;
                  }
              }
          }
          finally
          {
              m_done = true;
          }
      }
  
      public Throwable getException()
      {
          return m_exception;
      }
  
      boolean isDone()
      {
          return m_done;
      }
  
      boolean isInterupted()
      {
          return m_interupted;
      }
  
      synchronized void unlock()
      {
          m_locked = false;
          notifyAll();
      }
  
      private void doWork()
      {
          if( 0 != m_sleep )
          {
              try
              {
                  Thread.sleep( m_sleep );
              }
              catch( InterruptedException e )
              {
                  m_interupted = true;
              }
          }
          synchronized( this )
          {
              while( m_locked )
              {
                  try
                  {
                      wait( 100 );
                  }
                  catch( InterruptedException e )
                  {
                      e.printStackTrace();
                  }
              }
          }
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/test/org/codehaus/spice/threadpool/impl/commons-config.xml
  
  Index: commons-config.xml
  ===================================================================
  <root>
      <name>MyThreadPool</name>
      <priority>5</priority>
      <is-daemon>false</is-daemon>
      <resource-limiting>false</resource-limiting>
      <max-threads>10</max-threads>
      <max-idle>5</max-idle>
  </root>
  
  
  1.1                  spice/components/threadpool/src/test/org/codehaus/spice/threadpool/impl/PicoThreadPoolTestCase.java
  
  Index: PicoThreadPoolTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.codehaus.spice.threadpool.ThreadPool;
  
  /**
   *  A TestCase for the PicoCommonsThreadPool.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @author <a href="mailto:mauro.talevi at aquilonia.org">Mauro Talevi</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:45 $
   */
  public class PicoThreadPoolTestCase
      extends AbstractThreadPoolTestCase
  {
      public PicoThreadPoolTestCase( final String name )
      {
          super( name );
      }
  
      protected AbstractThreadPool createThreadPool() throws Exception
      {
         return new PicoCommonsThreadPool( new NullThreadPoolMonitor(), "testThreadPool", 5, false, false, 3, 1 );
      }
  
      protected AbstractThreadPool createThreadPoolWithDebug() throws Exception
      {
         return new PicoCommonsThreadPool( new NullThreadPoolMonitor(), "testThreadPool", 5, false, false, 3, 1 );
      }
  
      protected void destroyThreadPool( final ThreadPool threadPool ) throws Exception
      {
          final PicoCommonsThreadPool picoThreadPool = (PicoCommonsThreadPool)threadPool;
          picoThreadPool.shutdown();
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/test/org/codehaus/spice/threadpool/impl/AvalonThreadPoolTestCase.java
  
  Index: AvalonThreadPoolTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  import org.apache.avalon.framework.container.ContainerUtil;
  import org.apache.avalon.framework.logger.ConsoleLogger;
  import org.codehaus.spice.threadpool.ThreadPool;
  
  /**
   *  A TestCase for the AvalonCommonsThreadPool.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @author <a href="mailto:mauro.talevi at aquilonia.org">Mauro Talevi</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:45 $
   */
  public class AvalonThreadPoolTestCase
      extends AbstractThreadPoolTestCase
  {
      public AvalonThreadPoolTestCase( final String name )
      {
          super( name );
      }
  
      protected AbstractThreadPool createThreadPool() throws Exception
      {
          return createAvalonThreadPool( ConsoleLogger.LEVEL_DISABLED );
      }
  
      protected AbstractThreadPool createThreadPoolWithDebug() throws Exception
      {
          return createAvalonThreadPool( ConsoleLogger.LEVEL_DEBUG );
      }
  
      protected void destroyThreadPool( final ThreadPool threadPool ) throws Exception
      {
          ContainerUtil.shutdown( threadPool );
      }
  
      private AvalonCommonsThreadPool createAvalonThreadPool( final int debug ) throws Exception
      {
          final AvalonCommonsThreadPool threadPool = new AvalonCommonsThreadPool();
          ContainerUtil.enableLogging( threadPool, new ConsoleLogger( debug ) );
          DefaultConfiguration configuration = buildConfiguration();
          ContainerUtil.configure( threadPool, configuration );
          ContainerUtil.initialize( threadPool );
          return threadPool;
      }
  
      private DefaultConfiguration buildConfiguration()
      {
          final DefaultConfiguration configuration = new DefaultConfiguration( "root", "" );
          addChild( configuration, "name", "testThreadPool" );
          addChild( configuration, "priority", "5" );
          addChild( configuration, "is-daemon", "false" );
          addChild( configuration, "max-threads", "3" );
          addChild( configuration, "max-idle", "1" );
          return configuration;
      }
  
      private void addChild( final DefaultConfiguration configuration,
                             final String name,
                             final String value )
      {
          final DefaultConfiguration child = new DefaultConfiguration( name, "" );
          child.setValue( value );
          configuration.addChild( child );
      }
  }
  
  
  
  1.1                  spice/components/threadpool/src/test/org/codehaus/spice/threadpool/impl/ThreadPoolEntry.java
  
  Index: ThreadPoolEntry.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import org.codehaus.spice.threadpool.ThreadControl;
  
  /**
   * simpler holder for test data.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:45 $
   */
  class ThreadPoolEntry
  {
      ThreadControl m_control;
      Work m_work;
  }
  
  
  
  1.1                  spice/components/threadpool/src/test/org/codehaus/spice/threadpool/impl/AbstractThreadPoolTestCase.java
  
  Index: AbstractThreadPoolTestCase.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool.impl;
  
  import java.io.InputStream;
  
  import junit.framework.TestCase;
  
  import org.codehaus.spice.threadpool.Executable;
  import org.codehaus.spice.threadpool.ThreadPool;
  import org.realityforge.configkit.ConfigValidator;
  import org.realityforge.configkit.ConfigValidatorFactory;
  import org.realityforge.configkit.ValidateException;
  import org.xml.sax.ErrorHandler;
  
  /**
   *  An abtract TestCase for the ThreadPools.
   *  Provides functionality common to all ThreadPool TestCases.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @author <a href="mailto:mauro.talevi at aquilonia.org">Mauro Talevi</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:45 $
   */
  public abstract class AbstractThreadPoolTestCase
      extends TestCase
  {
      public AbstractThreadPoolTestCase( final String name )
      {
          super( name );
      }
  
      public void testSchemaValidation()
          throws Exception
      {
          final InputStream schema =
              getClass().getResourceAsStream( "CommonsThreadPool-schema.xml" );
          assertNotNull( "Schema file", schema );
          final ConfigValidator validator =
              ConfigValidatorFactory.create( "http://relaxng.org/ns/structure/1.0", schema );
          final InputStream config =
              getClass().getResourceAsStream( "commons-config.xml" );
          try
          {
              validator.validate( config, (ErrorHandler)null );
          }
          catch( ValidateException e )
          {
              fail( "Unexpected validation failure: " + e );
          }
      }
  
      public void testNullInCtor()
          throws Exception
      {
          try
          {
              new ExecutableRunnable( null );
              fail( "Expected a NPE" );
          }
          catch( NullPointerException e )
          {
              assertEquals( e.getMessage(), "runnable" );
          }
          try
          {
              new WorkerThread( createThreadPool(), Thread.currentThread().getThreadGroup(), null );
              fail( "Expected a NPE" );
          }
          catch( NullPointerException e )
          {
              assertEquals( e.getMessage(), "name" );
          }
          try
          {
              new WorkerThread( null, Thread.currentThread().getThreadGroup(), "blah" );
              fail( "Expected a NPE" );
          }
          catch( NullPointerException e )
          {
              assertEquals( e.getMessage(), "pool" );
          }
      }
  
      public void testThreadPool()
          throws Exception
      {
          final ThreadPool threadPool = createThreadPool();
          doTestThread( threadPool );
      }
  
      public void testThreadPoolWithNoEnd()
          throws Exception
      {
          final ThreadPool threadPool = createThreadPool();
          doTestThreadWithNoEnd( threadPool );
      }
  
      public void testThreadPoolWithDebug()
          throws Exception
      {
          final ThreadPool threadPool = createThreadPoolWithDebug();
          doTestThread( threadPool );
      }
  
      public void testThreadPoolWithDebugWithNoEnd()
          throws Exception
      {
          final ThreadPool threadPool = createThreadPoolWithDebug();
          doTestThreadWithNoEnd( threadPool );
      }
  
      private void doTestThread( final ThreadPool threadPool ) throws Exception
      {
          ThreadPoolEntry entry = null;
  
          //Just make sure we test run therunnable version aswell
          threadPool.execute( (Runnable)new Work( false, 0, null ) );
  
          entry = createEntry( threadPool, new Work( true, 0, null ) );
          verifyEntry( entry );
          entry.m_work.unlock();
          verifyEntry( entry );
          entry.m_control.join( 20 );
  
          entry = createEntry( threadPool, new Work( true, 0, null ) );
          verifyEntry( entry );
          entry.m_control.join( 20 );
          verifyEntry( entry );
          entry.m_work.unlock();
  
          entry = createEntry( threadPool, new Work( true, 0, null ) );
          verifyEntry( entry );
          entry.m_work.unlock();
          verifyEntry( entry );
          entry.m_control.interrupt();
  
          entry = createEntry( threadPool, new Work( true, 0, null ) );
          verifyEntry( entry );
          entry.m_control.interrupt();
          verifyEntry( entry );
          entry.m_work.unlock();
  
          createEntry( threadPool, new Work( false, 500, null ) );
          createEntry( threadPool, new Work( false, 500, null ) );
          createEntry( threadPool, new Work( false, 500, null ) );
          createEntry( threadPool, new Work( false, 500, null ) );
  
          //Sleep a second to allow reaper to remove some of those workers
          Thread.sleep( 1000 );
  
          entry = createEntry( threadPool, new Work( false, 50, new Exception() ) );
          entry.m_control.join( 500 );
          verifyEntry( entry );
  
          entry = createEntry( threadPool, new Work( false, 50, new ThreadDeath() ) );
          entry.m_control.join( 500 );
          verifyEntry( entry );
  
          destroyThreadPool( threadPool );
      }
  
      private void doTestThreadWithNoEnd( final ThreadPool threadPool ) throws Exception
      {
          ThreadPoolEntry entry = null;
          //Okay the following creates a thread that won't end
          //but we try to shutdown pull anyways - should not hang
          entry = createEntry( threadPool, new Work( true, 0, null ) );
          destroyThreadPool( threadPool );
  
          entry.m_work.unlock();
  
          //Sleep a second to allow an attempt to
          //recycle worker when pool disposed and thus
          //worker not "alive"
          Thread.sleep( 1000 );
      }
  
      private ThreadPoolEntry createEntry( final ThreadPool threadPool, final Work work )
      {
          final ThreadPoolEntry entry = new ThreadPoolEntry();
          entry.m_work = work;
          entry.m_control = threadPool.execute( (Executable)work );
          return entry;
      }
  
      private void verifyEntry( ThreadPoolEntry entry )
      {
          synchronized( entry.m_control )
          {
              final boolean finished = entry.m_control.isFinished();
              assertEquals( "Matching finished flags",
                            finished,
                            entry.m_work.isDone() );
  
              if( finished )
              {
                  assertEquals( "Matching exceptions",
                                entry.m_control.getThrowable(),
                                entry.m_work.getException() );
              }
              else
              {
                  assertNull( "Null exception for unfinished",
                              entry.m_control.getThrowable() );
              }
          }
      }
  
      protected abstract AbstractThreadPool createThreadPool() throws Exception;
  
      protected abstract AbstractThreadPool createThreadPoolWithDebug() throws Exception;
  
      protected abstract void destroyThreadPool( ThreadPool threadPool ) throws Exception;
  
  }
  
  
  
  1.7       +6 -6      spice/components/threadpool/xdocs/index.xml
  
  Index: index.xml
  ===================================================================
  RCS file: /scm/cvs/spice/components/threadpool/xdocs/index.xml,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- index.xml	5 Nov 2003 08:47:57 -0000	1.6
  +++ index.xml	20 Nov 2003 00:23:45 -0000	1.7
  @@ -30,9 +30,9 @@
                  supports type-1 Inversion of Control (IoC).
               </p>
               <p>
  -               <a href="apidocs/org/jcomponent/threadpool/impl/AvalonCommonsThreadPool.html">
  +               <a href="apidocs/org/codehaus/spice/threadpool/impl/AvalonCommonsThreadPool.html">
                     AvalonCommonsThreadPool</a> provides an implementation of the
  -               <a href="apidocs/org/jcomponent/threadpool/ThreadPool.html">
  +               <a href="apidocs/org/codehaus/spice/threadpool/ThreadPool.html">
                     ThreadPool</a> interface which is Avalon-compatible.
               </p>
            </subsection>
  @@ -42,9 +42,9 @@
                  supports type-1 Inversion of Control (IoC).
               </p>
               <p>
  -               <a href="apidocs/org/jcomponent/threadpool/impl/DNACommonsThreadPool.html">
  +               <a href="apidocs/org/codehaus/spice/threadpool/impl/DNACommonsThreadPool.html">
                     DNACommonsThreadPool</a> provides an implementation of the
  -               <a href="apidocs/org/jcomponent/threadpool/ThreadPool.html">
  +               <a href="apidocs/org/codehaus/spice/threadpool/ThreadPool.html">
                     ThreadPool</a> interface which is DNA-compatible.
               </p>
            </subsection>
  @@ -54,9 +54,9 @@
                  supports type-3 IoC.
               </p>
               <p>
  -               <a href="apidocs/org/jcomponent/threadpool/impl/PicoCommonsThreadPool.html">
  +               <a href="apidocs/org/codehaus/spice/threadpool/impl/PicoCommonsThreadPool.html">
                     PicoCommonsThreadPool</a> provides an implementation of the
  -               <a href="apidocs/org/jcomponent/threadpool/ThreadPool.html">
  +               <a href="apidocs/org/codehaus/spice/threadpool/ThreadPool.html">
                     ThreadPool</a> interface which is
                     <img src="http://www.picocontainer.org/images/pico-compatible.png" alt="Pico-compatible"/>.
               </p>
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/Executable.java
  
  Index: Executable.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool;
  
  /**
   * The Executable can be implemented by components that need to perform
   * some work. In many respects it is similar to Runnable except that it
   * also allows an application to throw a non-Runtime Exception.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:45 $
   */
  public interface Executable
  {
      /**
       * Execute the action.
       *
       * @throws Exception if an error occurs
       */
      void execute()
          throws Exception;
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/ThreadPoolMonitor.java
  
  Index: ThreadPoolMonitor.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
   package org.codehaus.spice.threadpool;
  
  /**
   * Monitor interface for ThreadPool.  
   * Provides a facade to support different types of events, including logging.
   * 
   * @author <a href="mailto:mauro.talevi at aquilonia.org">Mauro Talevi</a>
   * @author <a href="mailto:paul_hammant at yahoo.com">Paul Hammant</a>
   */
  public interface ThreadPoolMonitor
  {
     void newThreadPool( String name,
                         int priority,
                         boolean daemon,
                         int maxActive,
                         int maxIdle );
  
     void threadRetrieved( Thread thread );
  
     void threadReturned( Thread thread );
  
     void threadCreated( Thread thread );
  
     void threadDisposing( Thread thread );
  
     void unexpectedError( String message,
                            Throwable t );
  
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/ThreadControl.java
  
  Index: ThreadControl.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool;
  
  /**
   * This interface defines the method through which Threads can
   * be controlled.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:45 $
   */
  public interface ThreadControl
  {
      /**
       * Wait for specified time for thread to complete it's work.
       *
       * @param milliSeconds the duration in milliseconds to wait until the thread has finished work
       * @throws IllegalStateException if isValid() == false
       * @throws InterruptedException if another thread has interrupted the current thread.
       *            The interrupted status of the current thread is cleared when this exception
       *            is thrown.
       */
      void join( long milliSeconds )
          throws IllegalStateException, InterruptedException;
  
      /**
       * Call {@link Thread#interrupt()} on thread being controlled.
       *
       * @throws IllegalStateException if isValid() == false
       * @throws SecurityException if caller does not have permission to call interupt()
       */
      void interrupt()
          throws IllegalStateException, SecurityException;
  
      /**
       * Determine if thread has finished execution
       *
       * @return true if thread is finished, false otherwise
       */
      boolean isFinished();
  
      /**
       * Retrieve throwable that caused thread to cease execution.
       * Only valid when true == isFinished()
       *
       * @return the throwable that caused thread to finish execution
       */
      Throwable getThrowable();
  }
  
  
  
  1.1                  spice/components/threadpool/src/java/org/codehaus/spice/threadpool/ThreadPool.java
  
  Index: ThreadPool.java
  ===================================================================
  /*
   * Copyright (C) The Spice Group. All rights reserved.
   *
   * This software is published under the terms of the Spice
   * Software License version 1.1, a copy of which has been included
   * with this distribution in the LICENSE.txt file.
   */
  package org.codehaus.spice.threadpool;
  
  /**
   * This class is the public frontend for the thread pool code.
   *
   * @author <a href="mailto:peter at realityforge.org">Peter Donald</a>
   * @version $Revision: 1.1 $ $Date: 2003/11/20 00:23:45 $
   */
  public interface ThreadPool
  {
      /**
       * Run work in separate thread.
       * Return a valid ThreadControl to control work thread.
       *
       * @param work the work to be executed.
       * @return the ThreadControl
       */
      ThreadControl execute( Runnable work );
  
      /**
       * Run work in separate thread.
       * Return a valid ThreadControl to control work thread.
       *
       * @param work the work to be executed.
       * @return the ThreadControl
       */
      ThreadControl execute( Executable work );
  }
  
  
  
  1.16      +2 -2      spice/components/threadpool/project.xml
  
  Index: project.xml
  ===================================================================
  RCS file: /scm/cvs/spice/components/threadpool/project.xml,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- project.xml	19 Nov 2003 17:38:34 -0000	1.15
  +++ project.xml	20 Nov 2003 00:23:45 -0000	1.16
  @@ -4,8 +4,8 @@
       <name>ThreadPool</name>
       <id>spice-threadpool</id>
       <gumpRepositoryId>components</gumpRepositoryId>
  -    <package>org.jcomponent.threadpool</package>
  -    <currentVersion>1.0</currentVersion>
  +    <package>org.codehaus.spice.threadpool</package>
  +    <currentVersion>1.0-b1</currentVersion>
   
       <shortDescription>ThreadPool component</shortDescription>