This is an automated email from the ASF dual-hosted git repository. martin_s pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/archiva-redback-components-spring-taskqueue.git
commit 490913c031ed8646ced28df608cb0403ebcf3c80 Author: Olivier Lamy <[email protected]> AuthorDate: Fri Apr 6 09:33:40 2012 +0000 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 --- pom.xml | 78 +++++ .../plexus/taskqueue/DefaultTaskQueue.java | 221 ++++++++++++ .../java/org/codehaus/plexus/taskqueue/Task.java | 38 +++ .../plexus/taskqueue/TaskEntryEvaluator.java | 38 +++ .../plexus/taskqueue/TaskExitEvaluator.java | 38 +++ .../org/codehaus/plexus/taskqueue/TaskQueue.java | 82 +++++ .../plexus/taskqueue/TaskQueueException.java | 43 +++ .../plexus/taskqueue/TaskViabilityEvaluator.java | 45 +++ .../execution/TaskExecutionException.java | 43 +++ .../plexus/taskqueue/execution/TaskExecutor.java | 37 ++ .../taskqueue/execution/TaskQueueExecutor.java | 52 +++ .../execution/ThreadedTaskQueueExecutor.java | 378 +++++++++++++++++++++ src/main/resources/META-INF/spring-context.xml | 34 ++ .../plexus/taskqueue/ATaskEntryEvaluator.java | 42 +++ .../plexus/taskqueue/ATaskExitEvaluator.java | 42 +++ .../plexus/taskqueue/BTaskEntryEvaluator.java | 42 +++ .../plexus/taskqueue/BTaskExitEvaluator.java | 42 +++ .../plexus/taskqueue/BuildProjectTask.java | 160 +++++++++ .../BuildProjectTaskViabilityEvaluator.java | 68 ++++ .../codehaus/plexus/taskqueue/TaskQueueTest.java | 191 +++++++++++ .../execution/BuildProjectTaskExecutor.java | 81 +++++ .../taskqueue/execution/TaskQueueExecutorTest.java | 112 ++++++ src/test/resources/spring-context.xml | 66 ++++ 23 files changed, 1973 insertions(+) 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:[email protected]">Jason van Zyl</a> + * @author <a href="mailto:[email protected]">Trygve Laugstø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:[email protected]">Jason van Zyl</a> + * @author <a href="mailto:[email protected]">Trygve Laugstø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:[email protected]">Jason van Zyl</a> + * @author <a href="mailto:[email protected]">Trygve Laugstø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:[email protected]">Jason van Zyl</a> + * @author <a href="mailto:[email protected]">Trygve Laugstø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:[email protected]">Jason van Zyl</a> + * @author <a href="mailto:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstø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:[email protected]">Jason van Zyl</a> + * @author <a href="mailto:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstøl</a> + * @author <a href="mailto:[email protected]">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:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstø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:[email protected]">Trygve Laugstø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:[email protected]">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:[email protected]">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 -- To stop receiving notification emails like this one, please contact [email protected].
