pax_global_header 0000666 0000000 0000000 00000000064 11602207445 0014513 g ustar 00root root 0000000 0000000 52 comment=e28db510c4ed049089f9b848bebed85d5ad172db
jenkinsci-lib-task-reactor-fb38fe8/ 0000775 0000000 0000000 00000000000 11602207445 0017340 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/.gitignore 0000664 0000000 0000000 00000000031 11602207445 0021322 0 ustar 00root root 0000000 0000000 *.iml
*.ipr
*.iws
target
jenkinsci-lib-task-reactor-fb38fe8/pom.xml 0000664 0000000 0000000 00000002643 11602207445 0020662 0 ustar 00root root 0000000 0000000
4.0.0
org.jenkins-ci
jenkins
1.21
task-reactor
1.3
init
junit
junit
3.8.1
test
org.objectweb.carol
cmi
1.3.12
test
MIT License
http://jenkins-ci.org/mit-license
scm:git:git://github.com/jenkinsci/lib-task-reactor.git
scm:git:git@github.com:jenkinsci/lib-task-reactor.git
https://github.com/jenkinsci/lib-task-reactor
m.g.o-public
http://maven.glassfish.org/content/groups/public/
jenkinsci-lib-task-reactor-fb38fe8/src/ 0000775 0000000 0000000 00000000000 11602207445 0020127 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/main/ 0000775 0000000 0000000 00000000000 11602207445 0021053 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/main/java/ 0000775 0000000 0000000 00000000000 11602207445 0021774 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/ 0000775 0000000 0000000 00000000000 11602207445 0022563 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/ 0000775 0000000 0000000 00000000000 11602207445 0023711 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/ 0000775 0000000 0000000 00000000000 11602207445 0025211 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/ 0000775 0000000 0000000 00000000000 11602207445 0026650 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/Executable.java 0000664 0000000 0000000 00000003306 11602207445 0031576 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
/**
* Represents code that can be executed.
*
* @author Kohsuke Kawaguchi
*/
public interface Executable {
/**
* Executes a task. Any exception thrown will abort the session.
* @param reactor
*/
void run(Reactor reactor) throws Exception;
/**
* No-op implementation.
*/
public static final Executable NOOP = new Executable() {
public void run(Reactor reactor) throws Exception {
}
@Override
public String toString() {
return "noop";
}
};
}
jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/Milestone.java 0000664 0000000 0000000 00000002464 11602207445 0031460 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
/**
* Marker interface that indicates a milestone in the reactor process.
*
* @author Kohsuke Kawaguchi
*/
public interface Milestone {
}
jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/MilestoneImpl.java 0000664 0000000 0000000 00000004071 11602207445 0032276 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
/**
* Default {@link Milestone} implementation.
*
* @author Kohsuke Kawaguchi
*/
public class MilestoneImpl implements Milestone {
private final String id;
/**
* Compares equal with other {@link MilestoneImpl}s with the same ID.
*/
public MilestoneImpl(String id) {
this.id = id;
}
/**
* Only compare equal with this {@link MilestoneImpl} and nothing else.
*/
public MilestoneImpl() {
this(null);
}
public String toString() {
return id;
}
public int hashCode() {
return id!=null ? id.hashCode() : super.hashCode();
}
public boolean equals(Object obj) {
if (this==obj) return true;
if (obj instanceof MilestoneImpl) {
MilestoneImpl that = (MilestoneImpl) obj;
return this.id!=null && that.id!=null && this.id.equals(that.id);
}
return false;
}
}
jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/Reactor.java 0000664 0000000 0000000 00000020637 11602207445 0031122 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Executor;
/**
* Executes a set of {@link Task}s that dependend on each other.
*
*
* As a {@link Set}, this object represents a read-only view of all {@link Task}s.
*
* @author Kohsuke Kawaguchi
*/
public class Reactor implements Iterable {
/**
* {@link Node}s created from {@link Task}.
*/
private final Set tasks = new HashSet();
/**
* Number of tasks pending execution
*/
private int pending = 0;
/**
* RuntimeException or Error that indicates a fatal failure in a task
*/
private TunnelException fatal;
/**
* Milestones as nodes in DAG. Guarded by 'this'.
*/
private final Map milestones = new HashMap();
private Executor executor;
private ReactorListener listener;
private boolean executed = false;
/**
* A node in DAG.
*/
final class Node implements Runnable {
/**
* All of them have to run before this task can be executed.
*/
private final Set prerequisites = new HashSet();
/**
* What to run
*/
private final Runnable task;
/**
* These nodes have this node in {@link #prerequisites}.
*/
private final Set downstream = new HashSet();
private boolean submitted;
private boolean done;
private Node(Runnable task) {
this.task = task;
}
private void addPrerequisite(Node n) {
prerequisites.add(n);
n.downstream.add(this);
}
/**
* Can this node be executed?
*/
private boolean canRun() {
if (submitted || executor==null) return false;
for (Node n : prerequisites)
if (!n.done) return false;
return true;
}
public void run() {
try {
task.run();
} catch(TunnelException t) {
fatal = t;
} finally {
done = true;
}
// trigger downstream
synchronized (Reactor.this) {
if (fatal==null) {
for (Node n : downstream)
n.runIfPossible();
}
pending--;
Reactor.this.notify();
}
}
public void runIfPossible() {
if (!canRun()) return;
pending++;
submitted = true;
executor.execute(this);
}
@Override
public String toString() {
return task.toString();
}
}
public Reactor(Collection extends TaskBuilder> builders) throws IOException {
for (TaskBuilder b : builders)
for (Task t :b.discoverTasks(this))
add(t);
}
public Reactor(TaskBuilder... builders) throws IOException {
this(Arrays.asList(builders));
}
public Iterator iterator() {
return tasks.iterator();
}
public int size() {
return tasks.size();
}
public void execute(Executor e) throws InterruptedException, ReactorException {
execute(e, ReactorListener.NOOP);
}
private synchronized Node milestone(final Milestone m) {
Node n = milestones.get(m);
if (n==null) {
milestones.put(m,n=new Node(new Runnable() {
public void run() {
listener.onAttained(m);
}
public String toString() {
return "Milestone:"+m.toString();
}
}));
}
return n;
}
/**
* Adds a new {@link Task} to the reactor.
*
*
* This can be even invoked during execution.
*/
public void add(Task t) {
addAll(Collections.singleton(t));
}
/**
* Adds a set of taks to the reactor.
*
*
* When adding a series of related tasks, it's often necessary to add them as a bulk,
* or else the newly added task can start executing before its dependencies are added.
*/
public synchronized void addAll(Iterable extends Task> _tasks) {
List newNodes = new ArrayList();
for (final Task t : _tasks) {
Node n = new Node(new Runnable() {
public void run() {
listener.onTaskStarted(t);
try {
runTask(t);
listener.onTaskCompleted(t);
} catch (Throwable x) {
boolean fatal = t.failureIsFatal();
listener.onTaskFailed(t,x, fatal);
if (fatal)
throw new TunnelException(x);
}
}
public String toString() {
return "Task:"+t.getDisplayName();
}
});
for (Milestone req : t.requires())
n.addPrerequisite(milestone(req));
for (Milestone a : t.attains())
milestone(a).addPrerequisite(n);
tasks.add(n);
newNodes.add(n);
}
for (Node n : newNodes)
n.runIfPossible();
for (Node n : milestones.values())
n.runIfPossible();
}
/**
* Executes this initialization session with the given executor.
*
* @param e
* Used for executing {@link Task}s.
* @param listener
* Receives callbacks during the execution.
*
* @throws InterruptedException
* if this thread is interrupted while waiting for the execution of tasks to complete.
* @throws ReactorException
* if one of the tasks failed by throwing an exception. The caller is responsible for canceling
* existing {@link Task}s that are in progress in {@link Executor}, if that's desired.
*/
public synchronized void execute(final Executor e, final ReactorListener listener) throws InterruptedException, ReactorException {
if (executed) throw new IllegalStateException("This session is already executed");
executed = true;
this.executor = e;
this.listener = listener;
try {
// start everything that can run
for (Node n : tasks)
n.runIfPossible();
for (Node n : milestones.values())
n.runIfPossible();
// block until everything is done
while(pending>0) {
wait();
if (fatal!=null)
throw new ReactorException(fatal.getCause());
}
} finally {
// avoid memory leak
this.executor = null;
this.listener = null;
}
}
/**
* Can be overridden by the subtype to enclose the entire execution of the task.
*/
protected void runTask(Task t) throws Exception {
t.run(this);
}
}
jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/ReactorException.java 0000664 0000000 0000000 00000002636 11602207445 0033000 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
/**
* Used to tunnel application-thrown {@link Throwable} (Error or Exception) to the caller.
* @author Kohsuke Kawaguchi
*/
public class ReactorException extends Exception {
ReactorException(Throwable cause) {
super(cause);
}
}
jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/ReactorListener.java 0000664 0000000 0000000 00000007414 11602207445 0032626 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
import java.util.concurrent.Executor;
import java.util.Collection;
/**
* Receives callback during the {@link Reactor#execute(Executor, ReactorListener)}.
*
* The callback happens by using the threads of {@link Executor}, which means these callbacks
* can occur concurrently. The callee is responsible for synchronization, if that's desired.
*
* @author Kohsuke Kawaguchi
*/
public interface ReactorListener {
/**
* Notifies that the execution of the task is about to start.
*/
void onTaskStarted(Task t);
/**
* Notifies that the execution of the task is about to finish.
*
* This happens on the same thread that called {@link #onTaskStarted(Task)}.
*/
void onTaskCompleted(Task t);
/**
* Notifies that the execution of the task have failed with an exception.
*
* @param err
* Either {@link Error} or {@link Exception}, indicating the cause of the failure.
* @param fatal
* If true, this problem is {@linkplain Task#failureIsFatal() fatal}, and the reactor
* is going to terminate. If false, the reactor will continue executing after this failure.
*/
void onTaskFailed(Task t, Throwable err, boolean fatal);
/**
* Indicates that the following milestone was attained.
*/
void onAttained(Milestone milestone);
public static final ReactorListener NOOP = new ReactorListener() {
public void onTaskStarted(Task t) {
}
public void onTaskCompleted(Task t) {
}
public void onTaskFailed(Task t, Throwable err, boolean fatal) {
}
public void onAttained(Milestone milestone) {
}
};
/**
* Bundles multiple listeners into one.
*/
public static class Aggregator implements ReactorListener {
private final Collection listeners;
public Aggregator(Collection listeners) {
this.listeners = listeners;
}
public void onTaskStarted(Task t) {
for (ReactorListener listener : listeners)
listener.onTaskStarted(t);
}
public void onTaskCompleted(Task t) {
for (ReactorListener listener : listeners)
listener.onTaskCompleted(t);
}
public void onTaskFailed(Task t, Throwable err, boolean fatal) {
for (ReactorListener listener : listeners)
listener.onTaskFailed(t,err,fatal);
}
public void onAttained(Milestone milestone) {
for (ReactorListener listener : listeners)
listener.onAttained(milestone);
}
}
}
jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/Task.java 0000664 0000000 0000000 00000004472 11602207445 0030424 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
import java.util.Collection;
/**
* One initialization task
*
* @author Kohsuke Kawaguchi
*/
public interface Task extends Executable {
/**
* Indicates the milestones necessary before executing this.
*/
Collection extends Milestone> requires();
/**
* Indicates the milestones that this initializer contributes.
*
* A milestone is considered attained if all the initializers that attains the given milestone
* completes. So it works as a kind of join.
*/
Collection extends Milestone> attains();
/**
* Human readable description of this task. Used for progress report.
*
* @return
* null to indicate that this task doesn't have any significant to humans.
*/
String getDisplayName();
/**
* Returns true if the failure of this task is fatal and should break the reactor.
* If false, the failure is sent to the listener but the successive tasks will be
* started as if this task was successful (and eventually resulting in the completion
* of the reactor execution, provided that no other fatal failures occur.)
*/
boolean failureIsFatal();
}
jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/TaskBuilder.java 0000664 0000000 0000000 00000005452 11602207445 0031732 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static java.util.Arrays.asList;
/**
* Contributes {@link Task}s to a {@link Reactor} execution.
*
* @author Kohsuke Kawaguchi
*/
public abstract class TaskBuilder {
/**
* Returns all the tasks that this builder contributes to.
*/
public abstract Iterable extends Task> discoverTasks(Reactor reactor) throws IOException;
/**
* Creates a {@link TaskBuilder} that always discovers the given set of tasks.
*/
public static TaskBuilder fromTasks(final Collection extends Task> tasks) {
return new TaskBuilder() {
public Iterable extends Task> discoverTasks(Reactor reactor) throws IOException {
return tasks;
}
};
}
public static TaskBuilder union(final Iterable extends TaskBuilder> builders) {
return new TaskBuilder() {
public Iterable extends Task> discoverTasks(Reactor reactor) throws IOException {
List r = new ArrayList();
for (TaskBuilder b : builders)
for (Task t : b.discoverTasks(reactor))
r.add(t);
return r;
}
};
}
public static TaskBuilder union(TaskBuilder... builders) {
return union(asList(builders));
}
/**
* {@link TaskBuilder} that contributes no task.
*/
public static final TaskBuilder EMPTY_BUILDER = fromTasks(Collections.emptyList());
}
jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/TaskGraphBuilder.java 0000664 0000000 0000000 00000014515 11602207445 0032714 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
import java.io.IOException;
import java.util.Set;
import java.util.HashSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
/**
* Builder/fluent-API pattern to build up a series of related tasks.
*
* @author Kohsuke Kawaguchi
*/
public class TaskGraphBuilder extends TaskBuilder {
private final Set tasks = new HashSet();
private final List requiresForNextTask = new ArrayList();
private final List attainsForNextTask = new ArrayList();
private boolean fatalForNextTask = true;
private Handle last;
public Iterable extends Task> discoverTasks(Reactor reactor) throws IOException {
return Collections.unmodifiableSet(tasks);
}
/**
* Adds a new work unit and returns its handle, which can then be used to set up dependencies among them.
*
* @param displayName
* Display name of the task.
* @param e
* The actual work.
*/
public Handle add(String displayName, Executable e) {
TaskImpl t = new TaskImpl(displayName, e);
tasks.add(t);
t.requires(requiresForNextTask);
t.attains(attainsForNextTask);
t.fatal = fatalForNextTask;
// reset
requiresForNextTask.clear();
attainsForNextTask.clear();
fatalForNextTask = true;
last = t;
return t;
}
/**
* Indicates that the task to be added requires the completion of the last added task.
*/
public TaskGraphBuilder followedBy() {
return requires(last);
}
/**
* Given milestones will be set as pre-requisites for the next task to be added.
*/
public TaskGraphBuilder requires(Milestone... milestones) {
requiresForNextTask.addAll(Arrays.asList(milestones));
return this;
}
/**
* Given milestones will be set as achievements for the next task.
*/
public TaskGraphBuilder attains(Milestone... milestones) {
attainsForNextTask.addAll(Arrays.asList(milestones));
return this;
}
public TaskGraphBuilder notFatal() {
fatalForNextTask = false;
return this;
}
/**
* Handle to the task. Call methods on this interface to set up dependencies among tasks.
*
*
* This interface is the fluent interface pattern, and all the methods return {@code this} to enable chaining.
*/
public interface Handle extends Milestone {
/**
* Adds a pre-requisite to this task.
*/
Handle requires(Milestone m);
/**
* Adds pre-requisites to this task.
*/
Handle requires(Milestone... m);
Handle requires(Collection extends Milestone> m);
/**
* Designates that the execution of this task contributes to the given milestone.
*/
Handle attains(Milestone m);
Handle attains(Collection extends Milestone> m);
/**
* Returns the task that this handle represents.
*/
Task asTask();
/**
* Marks this task as non-fatal.
*
* See {@link Task#failureIsFatal()}.
*/
Task notFatal();
}
private static final class TaskImpl implements Task, Milestone, Handle {
private final String displayName;
private final Executable executable;
private final Set requires = new HashSet();
private final Set attains = new HashSet();
private boolean fatal;
private TaskImpl(String displayName, Executable executable) {
this.displayName = displayName;
this.executable = executable;
attains.add(this);
}
public Collection requires() {
return requires;
}
public Collection attains() {
return attains;
}
public String getDisplayName() {
return displayName;
}
public boolean failureIsFatal() {
return fatal;
}
public void run(Reactor reactor) throws Exception {
executable.run(reactor);
}
@Override
public String toString() {
return displayName;
}
//
// mutators
//
public Handle requires(Milestone m) {
if (m!=null)
requires.add(m);
return this;
}
public Handle requires(Milestone... ms) {
return requires(Arrays.asList(ms));
}
public Handle requires(Collection extends Milestone> ms) {
for (Milestone m : ms)
requires(m);
return this;
}
public Handle attains(Milestone m) {
attains.add(m);
return this;
}
public Handle attains(Collection extends Milestone> ms) {
for (Milestone m : ms)
attains(m);
return this;
}
public Task asTask() {
return this;
}
public Task notFatal() {
fatal = false;
return this;
}
}
}
jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/TunnelException.java 0000664 0000000 0000000 00000002501 11602207445 0032635 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
/**
* @author Kohsuke Kawaguchi
*/
class TunnelException extends RuntimeException {
TunnelException(Throwable cause) {
super(cause);
}
}
jenkinsci-lib-task-reactor-fb38fe8/src/test/ 0000775 0000000 0000000 00000000000 11602207445 0021106 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/test/java/ 0000775 0000000 0000000 00000000000 11602207445 0022027 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/test/java/org/ 0000775 0000000 0000000 00000000000 11602207445 0022616 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/test/java/org/jvnet/ 0000775 0000000 0000000 00000000000 11602207445 0023744 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/test/java/org/jvnet/hudson/ 0000775 0000000 0000000 00000000000 11602207445 0025244 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/test/java/org/jvnet/hudson/reactor/ 0000775 0000000 0000000 00000000000 11602207445 0026703 5 ustar 00root root 0000000 0000000 jenkinsci-lib-task-reactor-fb38fe8/src/test/java/org/jvnet/hudson/reactor/SessionTest.java 0000664 0000000 0000000 00000024754 11602207445 0032045 0 ustar 00root root 0000000 0000000 /*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc.
*
* 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.
*/
package org.jvnet.hudson.reactor;
import junit.framework.TestCase;
import org.objectweb.carol.cmi.test.TeeWriter;
import org.jvnet.hudson.reactor.TaskGraphBuilder.Handle;
import javax.naming.NamingException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;
/**
* @author Kohsuke Kawaguchi
*/
public class SessionTest extends TestCase {
/**
* Makes sure the ordering happens.
*/
public void testSequentialOrdering() throws Exception {
Reactor s = buildSession("->t1->m1 m1->t2->m2 m2->t3->",new TestTask() {
public void run(Reactor session, String id) throws Exception {
System.out.println(id);
}
});
assertEquals(3,s.size());
String sw = execute(s);
assertEquals("Started t1\nEnded t1\nAttained m1\nStarted t2\nEnded t2\nAttained m2\nStarted t3\nEnded t3\n", sw);
}
private String execute(Reactor s) throws Exception {
StringWriter sw = new StringWriter();
System.out.println("----");
final PrintWriter w = new PrintWriter(new TeeWriter(sw,new OutputStreamWriter(System.out)),true);
s.execute(Executors.newCachedThreadPool(),new ReactorListener() {
public synchronized void onTaskStarted(Task t) {
w.println("Started "+t.getDisplayName());
}
public synchronized void onTaskCompleted(Task t) {
w.println("Ended "+t.getDisplayName());
}
public synchronized void onTaskFailed(Task t, Throwable err, boolean fatal) {
w.println("Failed "+t.getDisplayName()+" with "+err);
}
public synchronized void onAttained(Milestone milestone) {
w.println("Attained "+milestone);
}
});
return sw.toString();
}
/**
* Makes sure tasks can be executed in parallel.
*/
public void testConcurrentExecution() throws Exception {
execute(buildSession("->t1-> ->t2->", createLatch(2)));
}
/**
* Scheduling of downstream jobs go through slightly different path, so test that too.
*/
public void testConcurrentExecution2() throws Exception {
execute(buildSession("->t1->m m->t2-> m->t3->", new TestTask() {
TestTask latch = createLatch(2);
public void run(Reactor reactor, String id) throws Exception {
if (id.equals("t1")) return;
latch.run(reactor, id);
}
}));
}
/**
* Is the exception properly forwarded?
*/
public void testFailure() throws Exception {
final Exception[] e = new Exception[1];
try {
execute(buildSession("->t1->", new TestTask() {
public void run(Reactor reactor, String id) throws Exception {
throw e[0]=new NamingException("Yep");
}
}));
fail();
} catch (ReactorException x) {
assertSame(e[0],x.getCause());
}
}
/**
* Dynamically add a new task that can run immediately.
*/
public void testDynamicTask() throws Exception {
final Reactor s = buildSession("->t1->m1 m1->t2->", new TestTask() {
public void run(Reactor session, String id) throws Exception {
if (id.equals("t2")) {
// should start running immediately because it's prerequisite is already met.
session.add(new TaskImpl("m1->t3->",this));
}
}
});
assertEquals(2,s.size());
String result = execute(s);
// one more task added during execution
assertEquals(3,s.size());
assertEquals("Started t1\nEnded t1\nAttained m1\nStarted t2\nEnded t2\nStarted t3\nEnded t3\n", result);
}
/**
* Dynamically add a new task that can be only run later
*/
public void testDynamicTask2() throws Exception {
final Reactor s = buildSession("->t1->m1 m1->t2->m2 m2->t3->m3", new TestTask() {
public void run(Reactor session, String id) throws Exception {
if (id.equals("t2")) {
// should block until m3 is attained
session.add(new TaskImpl("m3->t4->",this));
}
}
});
assertEquals(3,s.size());
String result = execute(s);
// one more task added during execution
assertEquals(4,s.size());
assertEquals("Started t1\n" +
"Ended t1\n" +
"Attained m1\n" +
"Started t2\n" +
"Ended t2\n" +
"Attained m2\n" +
"Started t3\n" +
"Ended t3\n" +
"Attained m3\n" +
"Started t4\n" +
"Ended t4\n", result);
}
/**
* Milestones that no one attains should be attained by default.
*/
public void testDanglingMilestone() throws Exception {
Reactor s = buildSession("m1->t1->m2",new TestTask() {
public void run(Reactor session, String id) throws Exception {
}
});
String result = execute(s);
assertEquals("Attained m1\nStarted t1\nEnded t1\nAttained m2\n",result);
}
/**
* Tasks that are non-fatal.
*/
public void testNonFatalTask() throws Exception {
TaskGraphBuilder g = new TaskGraphBuilder();
Handle h = g.notFatal().add("1st", new Executable() {
public void run(Reactor reactor) throws Exception {
throw new IllegalArgumentException(); // simulated failure
}
});
g.requires(h).add("2nd",new Executable() {
public void run(Reactor reactor) throws Exception {
}
});
String result = execute(new Reactor(g));
assertEquals(
"Started 1st\n" +
"Failed 1st with java.lang.IllegalArgumentException\n" +
"Attained 1st\n" +
"Started 2nd\n" +
"Ended 2nd\n" +
"Attained 2nd\n",result);
}
/**
* Creates {@link TestTask} that waits for multiple tasks to be blocked together.
*/
private TestTask createLatch(final int threshold) {
return new TestTask() {
final Object lock = new Object();
int pending = 0;
boolean go = false;
public void run(Reactor reactor, String id) throws InterruptedException {
synchronized (lock) {
pending++;
if (pending==threshold) {
// make sure two of us execute at the same time
go = true;
lock.notifyAll();
}
while (!go)
lock.wait();
}
}
};
}
interface TestTask {
void run(Reactor reactor, String id) throws Exception;
}
private Reactor buildSession(String spec, final TestTask work) throws Exception {
Collection tasks = new ArrayList();
for (String node : spec.split(" "))
tasks.add(new TaskImpl(node,work));
return new Reactor(TaskBuilder.fromTasks(tasks));
}
class TaskImpl implements Task {
final String id;
final Collection requires;
final Collection attains;
final TestTask work;
TaskImpl(String id, TestTask work) {
String[] tokens = id.split("->");
this.id = tokens[1];
// tricky handling necessary due to inconsistency in how split works
this.requires = adapt(tokens[0].length()==0 ? Collections.emptyList() : Arrays.asList(tokens[0].split(",")));
this.attains = adapt(tokens.length<3 ? Collections.emptyList() : Arrays.asList(tokens[2].split(",")));
this.work = work;
}
private Collection adapt(List strings) {
List r = new ArrayList();
for (String s : strings)
r.add(new MilestoneImpl(s));
return r;
}
public Collection requires() {
return requires;
}
public Collection attains() {
return attains;
}
public String getDisplayName() {
return id;
}
public void run(Reactor reactor) throws Exception {
work.run(reactor, id);
}
public boolean failureIsFatal() {
return true;
}
}
private static class MilestoneImpl implements Milestone {
private final String id;
private MilestoneImpl(String id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MilestoneImpl milestone = (MilestoneImpl) o;
return id.equals(milestone.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public String toString() {
return id;
}
}
}