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>
* <config>
* <name>MyThreadPool</name> <!-- base name of all threads -->
* <priority>5</priority> <!-- set to default priority -->
* <is-daemon>false</is-daemon> <!-- are threads daemon threads? -->
* <resource-limiting>false</resource-limiting> <!-- will pool block when max threads reached? -->
* <max-threads>10</max-threads>
* <max-idle>5</max-idle> <!-- maximum number of idle threads -->
* </config>
* </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>