import redback components sources
http://svn.codehaus.org/redback/components/trunk/ r1724.


git-svn-id: https://svn.apache.org/repos/asf/archiva/redback/redback-components/trunk@1310262 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..ab4aabd
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,78 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.codehaus.redback.components</groupId>
+    <artifactId>redback-components</artifactId>
+    <version>1.3-SNAPSHOT</version>
+    <relativePath>../redback-components-parent/pom.xml</relativePath>
+  </parent>  
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>spring-taskqueue</artifactId>
+  <name>Spring Task Queue</name>
+  <version>1.1-SNAPSHOT</version>
+
+  <url>http://redback.codehaus.org/components/${project.artifactId}</url>
+
+  <distributionManagement>
+    <site>
+      <id>codehaus.org</id>
+      <url>dav:https://dav.codehaus.org/redback/components/${project.artifactId}</url>
+    </site>
+  </distributionManagement>
+
+  <scm>
+    <connection>scm:svn:https://svn.codehaus.org/redback/components/trunk/spring-taskqueue</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/redback/components/trunk/spring-taskqueue</developerConnection>
+    <url>http://fisheye.codehaus.org/browse/redback/components/trunk/spring-taskqueue</url>
+  </scm>
+
+  <dependencies>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>javax.inject</groupId>
+      <artifactId>javax.inject</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>javax.annotation</groupId>
+      <artifactId>jsr250-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-beans</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context-support</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+</project>
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/DefaultTaskQueue.java b/src/main/java/org/codehaus/plexus/taskqueue/DefaultTaskQueue.java
new file mode 100644
index 0000000..810b579
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/DefaultTaskQueue.java
@@ -0,0 +1,221 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public class DefaultTaskQueue
+    implements TaskQueue
+{
+
+    private Logger logger = LoggerFactory.getLogger( getClass() );
+
+    private List<TaskEntryEvaluator> taskEntryEvaluators = new ArrayList<TaskEntryEvaluator>();
+
+    private List<TaskExitEvaluator> taskExitEvaluators = new ArrayList<TaskExitEvaluator>();
+
+    private List<TaskViabilityEvaluator> taskViabilityEvaluators = new ArrayList<TaskViabilityEvaluator>();
+
+    private BlockingQueue<Task> queue = new LinkedBlockingQueue<Task>();
+
+    // ----------------------------------------------------------------------
+    // Component Lifecycle
+    // ----------------------------------------------------------------------
+
+    // ----------------------------------------------------------------------
+    // TaskQueue Implementation
+    // ----------------------------------------------------------------------
+
+    // ----------------------------------------------------------------------
+    // Queue operations
+    // ----------------------------------------------------------------------
+
+    public boolean put( Task task )
+        throws TaskQueueException
+    {
+        // ----------------------------------------------------------------------
+        // Check that all the task entry evaluators accepts the task
+        // ----------------------------------------------------------------------
+
+        for ( TaskEntryEvaluator taskEntryEvaluator : taskEntryEvaluators )
+        {
+            boolean result = taskEntryEvaluator.evaluate( task );
+
+            if ( !result )
+            {
+                return false;
+            }
+        }
+
+        // ----------------------------------------------------------------------
+        // The task was accepted, enqueue it
+        // ----------------------------------------------------------------------
+
+        enqueue( task );
+
+        // ----------------------------------------------------------------------
+        // Check that all the task viability evaluators accepts the task
+        // ----------------------------------------------------------------------
+
+        for ( TaskViabilityEvaluator taskViabilityEvaluator : taskViabilityEvaluators )
+        {
+            Collection<Task> toBeRemoved =
+                taskViabilityEvaluator.evaluate( Collections.unmodifiableCollection( queue ) );
+
+            for ( Iterator<Task> it2 = toBeRemoved.iterator(); it2.hasNext(); )
+            {
+                Task t = it2.next();
+
+                queue.remove( t );
+            }
+        }
+
+        return true;
+    }
+
+    public Task take()
+        throws TaskQueueException
+    {
+        logger.debug( "take" );
+        while ( true )
+        {
+            Task task = dequeue();
+
+            if ( task == null )
+            {
+                return null;
+            }
+
+            for ( TaskExitEvaluator taskExitEvaluator : taskExitEvaluators )
+            {
+                boolean result = taskExitEvaluator.evaluate( task );
+
+                if ( !result )
+                {
+                    // the task wasn't accepted; drop it.
+                    task = null;
+
+                    break;
+                }
+            }
+
+            if ( task != null )
+            {
+                return task;
+            }
+        }
+    }
+
+    public Task poll( int timeout, TimeUnit timeUnit )
+        throws InterruptedException
+    {
+        logger.debug( "pool" );
+        return queue.poll( timeout, timeUnit );
+    }
+
+    public boolean remove( Task task )
+        throws ClassCastException, NullPointerException
+    {
+        return queue.remove( task );
+    }
+
+    public boolean removeAll( List tasks )
+        throws ClassCastException, NullPointerException
+    {
+        return queue.removeAll( tasks );
+    }
+
+    // ----------------------------------------------------------------------
+    // Queue Inspection
+    // ----------------------------------------------------------------------
+
+    public List<Task> getQueueSnapshot()
+        throws TaskQueueException
+    {
+        return Collections.unmodifiableList( new ArrayList( queue ) );
+    }
+
+    // ----------------------------------------------------------------------
+    // Queue Management
+    // ----------------------------------------------------------------------
+
+    private void enqueue( Task task )
+    {
+        boolean success = queue.add( task );
+        logger.debug( "enqueue success {}", success );
+    }
+
+    private Task dequeue()
+    {
+        logger.debug( "dequeue" );
+        return queue.poll();
+    }
+
+    public List<TaskEntryEvaluator> getTaskEntryEvaluators()
+    {
+        return taskEntryEvaluators;
+    }
+
+    public void setTaskEntryEvaluators( List<TaskEntryEvaluator> taskEntryEvaluators )
+    {
+        this.taskEntryEvaluators = taskEntryEvaluators;
+    }
+
+    public List<TaskExitEvaluator> getTaskExitEvaluators()
+    {
+        return taskExitEvaluators;
+    }
+
+    public void setTaskExitEvaluators( List<TaskExitEvaluator> taskExitEvaluators )
+    {
+        this.taskExitEvaluators = taskExitEvaluators;
+    }
+
+    public List<TaskViabilityEvaluator> getTaskViabilityEvaluators()
+    {
+        return taskViabilityEvaluators;
+    }
+
+    public void setTaskViabilityEvaluators( List<TaskViabilityEvaluator> taskViabilityEvaluators )
+    {
+        this.taskViabilityEvaluators = taskViabilityEvaluators;
+    }
+}
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/Task.java b/src/main/java/org/codehaus/plexus/taskqueue/Task.java
new file mode 100644
index 0000000..3dd3fdc
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/Task.java
@@ -0,0 +1,38 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public interface Task
+{
+    /**
+     * @return the maximum time in milliseconds this task may run before it's cancelled.
+     */
+    long getMaxExecutionTime();
+}
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/TaskEntryEvaluator.java b/src/main/java/org/codehaus/plexus/taskqueue/TaskEntryEvaluator.java
new file mode 100644
index 0000000..b732e10
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/TaskEntryEvaluator.java
@@ -0,0 +1,38 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public interface TaskEntryEvaluator
+{
+    String ROLE = TaskEntryEvaluator.class.getName();
+
+    boolean evaluate( Task task )
+        throws TaskQueueException;
+}
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/TaskExitEvaluator.java b/src/main/java/org/codehaus/plexus/taskqueue/TaskExitEvaluator.java
new file mode 100644
index 0000000..95dd907
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/TaskExitEvaluator.java
@@ -0,0 +1,38 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public interface TaskExitEvaluator
+{
+    String ROLE = TaskExitEvaluator.class.getName();
+
+    boolean evaluate( Task task )
+        throws TaskQueueException;
+}
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/TaskQueue.java b/src/main/java/org/codehaus/plexus/taskqueue/TaskQueue.java
new file mode 100644
index 0000000..832528c
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/TaskQueue.java
@@ -0,0 +1,82 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public interface TaskQueue
+{
+    String ROLE = TaskQueue.class.getName();
+
+    // ----------------------------------------------------------------------
+    // Queue operations
+    // ----------------------------------------------------------------------
+
+    /**
+     * @param task
+     *            The task to add to the queue.
+     * @return Returns true if the task was accepted into the queue.
+     */
+    boolean put( Task task )
+        throws TaskQueueException;
+
+    Task take()
+        throws TaskQueueException;
+
+    boolean remove( Task task )
+        throws ClassCastException, NullPointerException;
+    
+    boolean removeAll( List tasks )
+        throws ClassCastException, NullPointerException;
+
+    // ----------------------------------------------------------------------
+    // Queue Inspection
+    // ----------------------------------------------------------------------
+
+    List getQueueSnapshot()
+        throws TaskQueueException;
+
+    /**
+     * Retrieves and removes the head of the queue, waiting at most timeout timeUnit when no element is available.
+     *
+     * @param timeout
+     *            time to wait, in timeUnit units
+     * @param timeUnit
+     *            how to interpret the timeout parameter.
+     * @return the head of the queue, or null if the timeout elapsed
+     * @throws InterruptedException
+     *             when this thread is interrupted while waiting
+     */
+    Task poll( int timeout, TimeUnit timeUnit )
+        throws InterruptedException;
+}
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/TaskQueueException.java b/src/main/java/org/codehaus/plexus/taskqueue/TaskQueueException.java
new file mode 100644
index 0000000..c448906
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/TaskQueueException.java
@@ -0,0 +1,43 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public class TaskQueueException
+    extends Exception
+{
+    public TaskQueueException( String message )
+    {
+        super( message );
+    }
+
+    public TaskQueueException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/TaskViabilityEvaluator.java b/src/main/java/org/codehaus/plexus/taskqueue/TaskViabilityEvaluator.java
new file mode 100644
index 0000000..2ee2fc2
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/TaskViabilityEvaluator.java
@@ -0,0 +1,45 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import java.util.Collection;
+
+/**
+ * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public interface TaskViabilityEvaluator
+{
+    String ROLE = TaskViabilityEvaluator.class.getName();
+
+    /**
+     * @param tasks The tasks to evaluate
+     * @return Returns a list of tasks to remove from the queue.
+     * @throws TaskQueueException
+     */
+    Collection<Task> evaluate( Collection tasks )
+        throws TaskQueueException;
+}
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/execution/TaskExecutionException.java b/src/main/java/org/codehaus/plexus/taskqueue/execution/TaskExecutionException.java
new file mode 100644
index 0000000..aac0f81
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/execution/TaskExecutionException.java
@@ -0,0 +1,43 @@
+package org.codehaus.plexus.taskqueue.execution;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public class TaskExecutionException
+    extends Exception
+{
+    public TaskExecutionException( String message )
+    {
+        super( message );
+    }
+
+    public TaskExecutionException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/execution/TaskExecutor.java b/src/main/java/org/codehaus/plexus/taskqueue/execution/TaskExecutor.java
new file mode 100644
index 0000000..15bea9d
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/execution/TaskExecutor.java
@@ -0,0 +1,37 @@
+package org.codehaus.plexus.taskqueue.execution;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import org.codehaus.plexus.taskqueue.Task;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public interface TaskExecutor
+{
+    void executeTask( Task task )
+        throws TaskExecutionException;
+}
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/execution/TaskQueueExecutor.java b/src/main/java/org/codehaus/plexus/taskqueue/execution/TaskQueueExecutor.java
new file mode 100644
index 0000000..e097bc1
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/execution/TaskQueueExecutor.java
@@ -0,0 +1,52 @@
+package org.codehaus.plexus.taskqueue.execution;
+
+import org.codehaus.plexus.taskqueue.Task;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public interface TaskQueueExecutor
+{
+    String ROLE = TaskQueueExecutor.class.getName();
+
+    /**
+     * Returns the currently executing task.
+     *
+     * @return the currently executing task.
+     */
+    Task getCurrentTask();
+
+    /**
+     * Cancels execution of this task, if it's currently running.
+     * Does NOT remove it from the associated queue!
+     *
+     * @param task The task to cancel
+     * @return true if the task was cancelled, false if the task was not executing.
+     */
+    boolean cancelTask( Task task );
+}
diff --git a/src/main/java/org/codehaus/plexus/taskqueue/execution/ThreadedTaskQueueExecutor.java b/src/main/java/org/codehaus/plexus/taskqueue/execution/ThreadedTaskQueueExecutor.java
new file mode 100644
index 0000000..c827e18
--- /dev/null
+++ b/src/main/java/org/codehaus/plexus/taskqueue/execution/ThreadedTaskQueueExecutor.java
@@ -0,0 +1,378 @@
+package org.codehaus.plexus.taskqueue.execution;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import org.apache.commons.lang.StringUtils;
+import org.codehaus.plexus.taskqueue.Task;
+import org.codehaus.plexus.taskqueue.TaskQueue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @author <a href="mailto:kenney@codehaus.org">Kenney Westerhof</a>
+ * @version $Id$
+ */
+public class ThreadedTaskQueueExecutor
+    implements TaskQueueExecutor
+{
+
+    private Logger logger = LoggerFactory.getLogger( getClass() );
+
+    private static final int SHUTDOWN = 1;
+
+    private static final int CANCEL_TASK = 2;
+
+    /**
+     * requirement
+     */
+    private TaskQueue queue;
+
+    /**
+     * requirement
+     */
+    private TaskExecutor executor;
+
+    /**
+     * configuration
+     */
+    private String name;
+
+    // ----------------------------------------------------------------------
+    //
+    // ----------------------------------------------------------------------
+
+    private ExecutorRunnable executorRunnable;
+
+    private ExecutorService executorService;
+
+    private Task currentTask;
+
+    private class ExecutorRunnable
+        extends Thread
+    {
+        private volatile int command;
+
+        private boolean done;
+
+        public void run()
+        {
+            while ( command != SHUTDOWN )
+            {
+                final Task task;
+
+                currentTask = null;
+
+                try
+                {
+                    task = queue.poll( 100, TimeUnit.MILLISECONDS );
+                }
+                catch ( InterruptedException e )
+                {
+                    logger.info( "Executor thread interrupted, command: {}", ( command == SHUTDOWN
+                        ? "Shutdown"
+                        : command == CANCEL_TASK ? "Cancel task" : "Unknown" ) );
+                    continue;
+                }
+
+                if ( task == null )
+                {
+                    continue;
+                }
+
+                currentTask = task;
+
+                Future future = executorService.submit( new Runnable()
+                {
+                    public void run()
+                    {
+                        try
+                        {
+                            executor.executeTask( task );
+                        }
+                        catch ( TaskExecutionException e )
+                        {
+                            logger.error( "Error executing task", e );
+                        }
+                    }
+                } );
+
+                try
+                {
+                    waitForTask( task, future );
+                }
+                catch ( ExecutionException e )
+                {
+                    logger.error( "Error executing task", e );
+                }
+            }
+
+            currentTask = null;
+
+            logger.info( "Executor thread '{}' exited.", name );
+
+            done = true;
+
+            synchronized ( this )
+            {
+                notifyAll();
+            }
+        }
+
+        private void waitForTask( Task task, Future future )
+            throws ExecutionException
+        {
+            boolean stop = false;
+
+            while ( !stop )
+            {
+                try
+                {
+                    if ( task.getMaxExecutionTime() == 0 )
+                    {
+                        logger.debug( "Waiting indefinitely for task to complete" );
+                        future.get();
+                        return;
+                    }
+                    else
+                    {
+                        logger.debug( "Waiting at most {} ms for task completion", task.getMaxExecutionTime() );
+                        future.get( task.getMaxExecutionTime(), TimeUnit.MILLISECONDS );
+                        logger.debug( "Task completed within {} ms", task.getMaxExecutionTime() );
+                        return;
+                    }
+                }
+                catch ( InterruptedException e )
+                {
+                    switch ( command )
+                    {
+                        case SHUTDOWN:
+                        {
+                            logger.info( "Shutdown command received. Cancelling task." );
+                            cancel( future );
+                            return;
+                        }
+
+                        case CANCEL_TASK:
+                        {
+                            command = 0;
+                            logger.info( "Cancelling task" );
+                            cancel( future );
+                            return;
+                        }
+
+                        default:
+                            // when can this thread be interrupted, and should we ignore it if shutdown = false?
+                            logger.warn( "Interrupted while waiting for task to complete; ignoring", e );
+                            break;
+                    }
+                }
+                catch ( TimeoutException e )
+                {
+                    logger.warn( "Task {} didn't complete within time, cancelling it.", task );
+                    cancel( future );
+                    return;
+                }
+                catch ( CancellationException e )
+                {
+                    logger.warn( "The task was cancelled", e );
+                    return;
+                }
+            }
+        }
+
+        private void cancel( Future future )
+        {
+            if ( !future.cancel( true ) )
+            {
+                if ( !future.isDone() && !future.isCancelled() )
+                {
+                    logger.warn( "Unable to cancel task" );
+                }
+                else
+                {
+                    logger.warn(
+                        "Task not cancelled (Flags: done: " + future.isDone() + " cancelled: " + future.isCancelled()
+                            + ")" );
+                }
+            }
+            else
+            {
+                logger.debug( "Task successfully cancelled" );
+            }
+        }
+
+        public synchronized void shutdown()
+        {
+            logger.debug( "Signalling executor thread to shutdown" );
+
+            command = SHUTDOWN;
+
+            interrupt();
+        }
+
+        public synchronized boolean cancelTask( Task task )
+        {
+            if ( !task.equals( currentTask ) )
+            {
+                logger.debug( "Not cancelling task - it is not running" );
+                return false;
+            }
+
+            if ( command != SHUTDOWN )
+            {
+                logger.debug( "Signalling executor thread to cancel task" );
+
+                command = CANCEL_TASK;
+
+                interrupt();
+            }
+            else
+            {
+                logger.debug( "Executor thread already stopping; task will be cancelled automatically" );
+            }
+
+            return true;
+        }
+
+        public boolean isDone()
+        {
+            return done;
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    // Component lifecycle
+    // ----------------------------------------------------------------------
+
+    @PostConstruct
+    public void start()
+    {
+
+        if ( StringUtils.isBlank( name ) )
+        {
+            throw new IllegalArgumentException( "'name' must be set." );
+        }
+
+        logger.info( "Starting task executor, thread name '{}'.", name );
+
+        this.executorService = Executors.newSingleThreadExecutor();
+
+        executorRunnable = new ExecutorRunnable();
+
+        executorRunnable.setDaemon( true );
+
+        executorRunnable.start();
+    }
+
+    @PreDestroy
+    public void stop()
+    {
+        executorRunnable.shutdown();
+
+        int maxSleep = 10 * 1000; // 10 seconds
+
+        int interval = 1000;
+
+        long endTime = System.currentTimeMillis() + maxSleep;
+
+        while ( !executorRunnable.isDone() && executorRunnable.isAlive() )
+        {
+            if ( System.currentTimeMillis() > endTime )
+            {
+                logger.warn( "Timeout waiting for executor thread '" + name + "' to stop, aborting" );
+                break;
+            }
+
+            logger.info( "Waiting until task executor '" + name + "' is idling..." );
+
+            try
+            {
+                synchronized ( executorRunnable )
+                {
+                    executorRunnable.wait( interval );
+                }
+            }
+            catch ( InterruptedException ex )
+            {
+                // ignore
+            }
+
+            // notify again, just in case.
+            executorRunnable.shutdown();
+        }
+    }
+
+    public Task getCurrentTask()
+    {
+        return currentTask;
+    }
+
+    public synchronized boolean cancelTask( Task task )
+    {
+        return executorRunnable.cancelTask( task );
+    }
+
+    public TaskQueue getQueue()
+    {
+        return queue;
+    }
+
+    public void setQueue( TaskQueue queue )
+    {
+        this.queue = queue;
+    }
+
+    public TaskExecutor getExecutor()
+    {
+        return executor;
+    }
+
+    public void setExecutor( TaskExecutor executor )
+    {
+        this.executor = executor;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+}
diff --git a/src/main/resources/META-INF/spring-context.xml b/src/main/resources/META-INF/spring-context.xml
new file mode 100755
index 0000000..08cf61b
--- /dev/null
+++ b/src/main/resources/META-INF/spring-context.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+           http://www.springframework.org/schema/context 
+           http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+       default-lazy-init="true">
+
+  <context:annotation-config />
+  <context:component-scan
+    base-package="org.codehaus.plexus.taskqueue"/>
+
+</beans>
\ No newline at end of file
diff --git a/src/test/java/org/codehaus/plexus/taskqueue/ATaskEntryEvaluator.java b/src/test/java/org/codehaus/plexus/taskqueue/ATaskEntryEvaluator.java
new file mode 100644
index 0000000..3a90140
--- /dev/null
+++ b/src/test/java/org/codehaus/plexus/taskqueue/ATaskEntryEvaluator.java
@@ -0,0 +1,42 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import org.springframework.stereotype.Service;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+@Service("taskEntryEvaluator#a")
+public class ATaskEntryEvaluator
+    implements TaskEntryEvaluator
+{
+    public boolean evaluate( Task task )
+        throws TaskQueueException
+    {
+        return ( (BuildProjectTask) task).isPassAEntryEvaluator();
+    }
+}
diff --git a/src/test/java/org/codehaus/plexus/taskqueue/ATaskExitEvaluator.java b/src/test/java/org/codehaus/plexus/taskqueue/ATaskExitEvaluator.java
new file mode 100644
index 0000000..0effd93
--- /dev/null
+++ b/src/test/java/org/codehaus/plexus/taskqueue/ATaskExitEvaluator.java
@@ -0,0 +1,42 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import org.springframework.stereotype.Service;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+@Service("taskExitEvaluator#a")
+public class ATaskExitEvaluator
+    implements TaskExitEvaluator
+{
+    public boolean evaluate( Task task )
+        throws TaskQueueException
+    {
+        return ( (BuildProjectTask) task ).isPassAExitEvaluator();
+    }
+}
diff --git a/src/test/java/org/codehaus/plexus/taskqueue/BTaskEntryEvaluator.java b/src/test/java/org/codehaus/plexus/taskqueue/BTaskEntryEvaluator.java
new file mode 100644
index 0000000..591e176
--- /dev/null
+++ b/src/test/java/org/codehaus/plexus/taskqueue/BTaskEntryEvaluator.java
@@ -0,0 +1,42 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import org.springframework.stereotype.Service;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+@Service("taskEntryEvaluator#b")
+public class BTaskEntryEvaluator
+    implements TaskEntryEvaluator
+{
+    public boolean evaluate( Task task )
+        throws TaskQueueException
+    {
+        return ( (BuildProjectTask) task ).isPassBEntryEvaluator();
+    }
+}
diff --git a/src/test/java/org/codehaus/plexus/taskqueue/BTaskExitEvaluator.java b/src/test/java/org/codehaus/plexus/taskqueue/BTaskExitEvaluator.java
new file mode 100644
index 0000000..367bbb4
--- /dev/null
+++ b/src/test/java/org/codehaus/plexus/taskqueue/BTaskExitEvaluator.java
@@ -0,0 +1,42 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import org.springframework.stereotype.Service;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+@Service("taskExitEvaluator#b")
+public class BTaskExitEvaluator
+    implements TaskExitEvaluator
+{
+    public boolean evaluate( Task task )
+        throws TaskQueueException
+    {
+        return ( (BuildProjectTask) task ).isPassBExitEvaluator();
+    }
+}
diff --git a/src/test/java/org/codehaus/plexus/taskqueue/BuildProjectTask.java b/src/test/java/org/codehaus/plexus/taskqueue/BuildProjectTask.java
new file mode 100644
index 0000000..c2f1a82
--- /dev/null
+++ b/src/test/java/org/codehaus/plexus/taskqueue/BuildProjectTask.java
@@ -0,0 +1,160 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+public class BuildProjectTask
+    implements Task
+{
+    private boolean passAEntryEvaluator;
+
+    private boolean passBEntryEvaluator;
+
+    private boolean passAExitEvaluator;
+
+    private boolean passBExitEvaluator;
+
+    private long timestamp;
+
+    private long maxExecutionTime;
+
+    private long executionTime;
+
+    private boolean cancelled;
+
+    private boolean done;
+
+    private boolean started;
+
+    private boolean ignoreInterrupts;
+
+    public BuildProjectTask( boolean passAEntryEvaluator, boolean passBEntryEvaluator, boolean passAExitEvaluator,
+                             boolean passBExitEvaluator )
+    {
+        this.passAEntryEvaluator = passAEntryEvaluator;
+
+        this.passBEntryEvaluator = passBEntryEvaluator;
+
+        this.passAExitEvaluator = passAExitEvaluator;
+
+        this.passBExitEvaluator = passBExitEvaluator;
+    }
+
+    public BuildProjectTask( long timestamp )
+    {
+        this( true, true, true, true );
+
+        this.timestamp = timestamp;
+    }
+
+    public boolean isPassAEntryEvaluator()
+    {
+        return passAEntryEvaluator;
+    }
+
+    public boolean isPassBEntryEvaluator()
+    {
+        return passBEntryEvaluator;
+    }
+
+    public boolean isPassAExitEvaluator()
+    {
+        return passAExitEvaluator;
+    }
+
+    public boolean isPassBExitEvaluator()
+    {
+        return passBExitEvaluator;
+    }
+
+    public long getTimestamp()
+    {
+        return timestamp;
+    }
+
+    public long getMaxExecutionTime()
+    {
+        return maxExecutionTime;
+    }
+
+    public void setMaxExecutionTime( long timeout )
+    {
+        maxExecutionTime = timeout;
+    }
+
+    public void setExecutionTime( long l )
+    {
+        this.executionTime = l;
+    }
+
+    public long getExecutionTime()
+    {
+        return executionTime;
+    }
+
+    public boolean isCancelled()
+    {
+        return cancelled;
+    }
+
+    public void cancel()
+    {
+        cancelled = true;
+    }
+
+    public void done()
+    {
+        this.done = true;
+    }
+
+    public boolean isDone()
+    {
+        return done;
+    }
+
+    public boolean isStarted()
+    {
+        return started;
+    }
+
+    public void start()
+    {
+        this.started = true;
+    }
+
+    public void setIgnoreInterrupts( boolean ignore )
+    {
+        this.ignoreInterrupts = ignore;
+    }
+
+    public boolean ignoreInterrupts()
+    {
+        return ignoreInterrupts;
+    }
+
+}
diff --git a/src/test/java/org/codehaus/plexus/taskqueue/BuildProjectTaskViabilityEvaluator.java b/src/test/java/org/codehaus/plexus/taskqueue/BuildProjectTaskViabilityEvaluator.java
new file mode 100644
index 0000000..222dab4
--- /dev/null
+++ b/src/test/java/org/codehaus/plexus/taskqueue/BuildProjectTaskViabilityEvaluator.java
@@ -0,0 +1,68 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+@Service( "taskViabilityEvaluator#build-project" )
+public class BuildProjectTaskViabilityEvaluator
+    implements TaskViabilityEvaluator
+{
+    public Collection evaluate( Collection tasks )
+        throws TaskQueueException
+    {
+        BuildProjectTask okTask = null;
+
+        List toBeRemoved = new ArrayList( tasks.size() );
+
+        for ( Iterator it = tasks.iterator(); it.hasNext(); )
+        {
+            BuildProjectTask buildProjectTask = (BuildProjectTask) it.next();
+
+            if ( okTask == null )
+            {
+                okTask = buildProjectTask;
+
+                continue;
+            }
+
+            if ( buildProjectTask.getTimestamp() - okTask.getTimestamp() < 100 )
+            {
+                toBeRemoved.add( buildProjectTask );
+            }
+        }
+
+        return toBeRemoved;
+    }
+}
diff --git a/src/test/java/org/codehaus/plexus/taskqueue/TaskQueueTest.java b/src/test/java/org/codehaus/plexus/taskqueue/TaskQueueTest.java
new file mode 100644
index 0000000..7465ffe
--- /dev/null
+++ b/src/test/java/org/codehaus/plexus/taskqueue/TaskQueueTest.java
@@ -0,0 +1,191 @@
+package org.codehaus.plexus.taskqueue;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.backportconcurrent.ThreadPoolTaskExecutor;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id$
+ */
+@RunWith( SpringJUnit4ClassRunner.class )
+@ContextConfiguration( locations = { "classpath*:/META-INF/spring-context.xml", "classpath*:/spring-context.xml" } )
+public class TaskQueueTest
+    extends TestCase
+{
+    @Inject
+    @Named( value = "taskQueue#taskQueueTest" )
+    private TaskQueue taskQueue;
+
+
+    // NOTE: If we were using a blocking queue, the sleep/continue in the ThreadedTaskQueueExecutor wouldn't
+    // be necessary; the queue would block until an element was available.
+    @Test
+    public void testEmptyQueue()
+        throws Exception
+    {
+        assertNull( taskQueue.take() );
+    }
+
+    @Test
+    public void testTaskEntryAndExitEvaluators()
+        throws Exception
+    {
+        assertTaskIsAccepted( new BuildProjectTask( true, true, true, true ) );
+
+        assertTaskIsRejected( new BuildProjectTask( false, true, true, true ) );
+
+        assertTaskIsRejected( new BuildProjectTask( true, false, true, true ) );
+
+        assertTaskIsRejected( new BuildProjectTask( true, true, false, true ) );
+
+        assertTaskIsRejected( new BuildProjectTask( true, true, true, false ) );
+    }
+
+    @Test
+    public void testTaskViabilityEvaluators()
+        throws Exception
+    {
+        // The first and last task should be accepted
+
+        Task task1 = new BuildProjectTask( 0 );
+
+        Task task2 = new BuildProjectTask( 10 );
+
+        Task task3 = new BuildProjectTask( 20 );
+
+        Task task4 = new BuildProjectTask( 30 );
+
+        Task task5 = new BuildProjectTask( 40 );
+
+        Task task6 = new BuildProjectTask( 100 );
+
+        assertTrue( taskQueue.put( task1 ) );
+
+        assertTrue( taskQueue.put( task2 ) );
+
+        assertTrue( taskQueue.put( task3 ) );
+
+        assertTrue( taskQueue.put( task4 ) );
+
+        assertTrue( taskQueue.put( task5 ) );
+
+        assertTrue( taskQueue.put( task6 ) );
+
+        Task actualTask1 = taskQueue.take();
+
+        assertNotNull( actualTask1 );
+
+        assertEquals( task1, actualTask1 );
+
+        Task actualTask6 = taskQueue.take();
+
+        assertNotNull( actualTask6 );
+
+        assertEquals( task6, actualTask6 );
+
+        assertNull( taskQueue.take() );
+    }
+
+    @Test
+    public void testRemoveTask()
+        throws Exception
+    {
+        Task task = new BuildProjectTask( 0 );
+
+        taskQueue.put( task );
+
+        taskQueue.remove( task );
+
+        assertNull( taskQueue.take() );
+    }
+
+    @Test
+    public void testRemoveAll()
+        throws Exception
+    {
+
+        BlockingQueue<String> foo = new LinkedBlockingQueue<String>();
+        foo.offer("1");
+        foo.offer("2");
+
+        Task firstTask = new BuildProjectTask( 110 );
+
+        taskQueue.put( firstTask );
+
+        Task secondTask = new BuildProjectTask( 11120 );
+
+        taskQueue.put( secondTask );
+
+        assertEquals( 2, taskQueue.getQueueSnapshot().size() );
+
+        List tasks = new ArrayList();
+
+        tasks.add( firstTask );
+
+        tasks.add( secondTask );
+
+        taskQueue.removeAll( tasks );
+
+        assertTrue( taskQueue.getQueueSnapshot().isEmpty() );
+    }
+
+    // ----------------------------------------------------------------------
+    //
+    // ----------------------------------------------------------------------
+
+    private void assertTaskIsAccepted( Task expectedTask )
+        throws Exception
+    {
+        taskQueue.put( expectedTask );
+
+        Task actualTask = taskQueue.take();
+
+        assertEquals( expectedTask, actualTask );
+    }
+
+    private void assertTaskIsRejected( Task expectedTask )
+        throws Exception
+    {
+        taskQueue.put( expectedTask );
+
+        Task actualTask = taskQueue.take();
+
+        assertNull( actualTask );
+    }
+}
diff --git a/src/test/java/org/codehaus/plexus/taskqueue/execution/BuildProjectTaskExecutor.java b/src/test/java/org/codehaus/plexus/taskqueue/execution/BuildProjectTaskExecutor.java
new file mode 100644
index 0000000..cd05683
--- /dev/null
+++ b/src/test/java/org/codehaus/plexus/taskqueue/execution/BuildProjectTaskExecutor.java
@@ -0,0 +1,81 @@
+package org.codehaus.plexus.taskqueue.execution;
+
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.codehaus.plexus.taskqueue.BuildProjectTask;
+import org.codehaus.plexus.taskqueue.Task;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
+ *
+ */
+@Service("taskExecutor#build-project")
+public class BuildProjectTaskExecutor
+    implements TaskExecutor
+{
+
+    private Logger logger = LoggerFactory.getLogger( getClass() );
+
+    public void executeTask( Task task0 )
+        throws TaskExecutionException
+    {
+        BuildProjectTask task = (BuildProjectTask) task0;
+
+        task.start();
+
+        logger.info( "Task: " + task + " cancelled: " + task.isCancelled() + "; done: " + task.isDone() );
+
+        long time = System.currentTimeMillis();
+
+        long endTime = task.getExecutionTime() + time;
+
+        for ( long timeToSleep = endTime - time; timeToSleep > 0; timeToSleep = endTime - System.currentTimeMillis() )
+        {
+            try
+            {
+                logger.info( "Sleeping " + timeToSleep + "ms (interrupts ignored: " + task.ignoreInterrupts() + ")" );
+                Thread.sleep( timeToSleep );
+
+                task.done();
+
+                logger.info( "Task completed normally: " + task + " cancelled: " + task.isCancelled() + "; done: "
+                                 + task.isDone() );
+            }
+            catch ( InterruptedException e )
+            {
+                if ( !task.ignoreInterrupts() )
+                {
+                    task.cancel();
+
+                    logger.info(
+                        "Task cancelled: " + task + " cancelled: " + task.isCancelled() + "; done: " + task.isDone() );
+
+                    throw new TaskExecutionException( "Never interrupt sleeping threads! :)", e );
+                }
+                else
+                {
+                    logger.info( "Ignoring interrupt" );
+                }
+            }
+        }
+
+    }
+}
diff --git a/src/test/java/org/codehaus/plexus/taskqueue/execution/TaskQueueExecutorTest.java b/src/test/java/org/codehaus/plexus/taskqueue/execution/TaskQueueExecutorTest.java
new file mode 100644
index 0000000..ae1ed0c
--- /dev/null
+++ b/src/test/java/org/codehaus/plexus/taskqueue/execution/TaskQueueExecutorTest.java
@@ -0,0 +1,112 @@
+package org.codehaus.plexus.taskqueue.execution;
+
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2004, The Codehaus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import junit.framework.TestCase;
+import org.codehaus.plexus.taskqueue.BuildProjectTask;
+import org.codehaus.plexus.taskqueue.TaskQueue;
+import org.codehaus.plexus.taskqueue.TaskQueueException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
+ */
+@RunWith( SpringJUnit4ClassRunner.class )
+@ContextConfiguration( locations = { "classpath*:/META-INF/spring-context.xml", "classpath*:/spring-context.xml" } )
+public class TaskQueueExecutorTest
+    extends TestCase
+{
+    @Inject
+    @Named( value = "taskQueue#default" )
+    private TaskQueue taskQueue;
+
+    // inject this to start the executor see @PostConstruct in {@link ThreadedTaskQueueExecutor
+    @Inject
+    @Named( value = "queueExecutor#default" )
+    private TaskQueueExecutor taskQueueExecutor;
+
+
+    @Test
+    public void testTimeoutWithInterrupts()
+        throws TaskQueueException, InterruptedException
+    {
+        BuildProjectTask task = putTask( 2 * 1000, false );
+
+        waitForExpectedTaskEnd( task );
+
+        assertTrue( task.isCancelled() );
+        assertFalse( task.isDone() );
+    }
+
+    @Test
+    public void testTimeoutWithoutInterrupts()
+        throws TaskQueueException, InterruptedException
+    {
+        BuildProjectTask task = putTask( 2 * 1000, true );
+
+        waitForExpectedTaskEnd( task );
+
+        // the thread is killed so the task is neither done nor cancelled
+        assertFalse( task.isCancelled() );
+        assertFalse( task.isDone() );
+    }
+
+    private BuildProjectTask putTask( int executionTime, boolean ignoreInterrupts )
+        throws TaskQueueException
+    {
+        BuildProjectTask task = new BuildProjectTask( 100 );
+        task.setMaxExecutionTime( executionTime );
+        task.setExecutionTime( 10 * executionTime );
+        task.setIgnoreInterrupts( ignoreInterrupts );
+
+        taskQueue.put( task );
+        return task;
+    }
+
+    private static void waitForExpectedTaskEnd( BuildProjectTask task )
+        throws InterruptedException
+    {
+        // thread scheduling may take some time, so we want to wait until the task
+        // is actually running before starting to count the timeout.
+        for ( int i = 0; i < 500; i++ )
+        {
+            if ( task.isStarted() )
+            {
+                break;
+            }
+            Thread.sleep( 10 );
+        }
+
+        assertTrue( "Task not started in 5 seconds - heavy load?", task.isStarted() );
+
+        Thread.sleep( task.getMaxExecutionTime() );
+    }
+}
diff --git a/src/test/resources/spring-context.xml b/src/test/resources/spring-context.xml
new file mode 100644
index 0000000..ad66c03
--- /dev/null
+++ b/src/test/resources/spring-context.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+           http://www.springframework.org/schema/context 
+           http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+       default-lazy-init="true">
+
+  <bean name="queueExecutor#default" class="org.codehaus.plexus.taskqueue.execution.ThreadedTaskQueueExecutor">
+    <property name="queue" ref="taskQueue#default"/>
+    <property name="executor" ref="taskExecutor#build-project"/>
+    <property name="name" value="default"/>
+  </bean>
+
+  <bean name="queueExecutor#taskQueueTest" class="org.codehaus.plexus.taskqueue.execution.ThreadedTaskQueueExecutor">
+    <property name="queue" ref="taskQueue#taskQueueTest"/>
+    <property name="executor" ref="taskExecutor#build-project"/>
+    <property name="name" value="taskQueueTest"/>
+  </bean>
+
+  <bean abstract="true" name="abstractQueue" class="org.codehaus.plexus.taskqueue.DefaultTaskQueue">
+    <property name="taskEntryEvaluators">
+      <list>
+        <ref bean="taskEntryEvaluator#a"/>
+        <ref bean="taskEntryEvaluator#b"/>
+      </list>
+    </property>
+    <property name="taskExitEvaluators">
+      <list>
+        <ref bean="taskExitEvaluator#a"/>
+        <ref bean="taskExitEvaluator#b"/>
+      </list>
+    </property>
+    <property name="taskViabilityEvaluators">
+      <list>
+        <ref bean="taskViabilityEvaluator#build-project"/>
+      </list>
+    </property>
+  </bean>
+
+  <bean name="taskQueue#default" parent="abstractQueue"/>
+
+  <bean name="taskQueue#taskQueueTest" parent="abstractQueue"/>
+
+</beans>
\ No newline at end of file