pax_global_header00006660000000000000000000000064116022074450014513gustar00rootroot0000000000000052 comment=e28db510c4ed049089f9b848bebed85d5ad172db jenkinsci-lib-task-reactor-fb38fe8/000077500000000000000000000000001160220744500173405ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/.gitignore000066400000000000000000000000311160220744500213220ustar00rootroot00000000000000*.iml *.ipr *.iws target jenkinsci-lib-task-reactor-fb38fe8/pom.xml000066400000000000000000000026431160220744500206620ustar00rootroot00000000000000 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/000077500000000000000000000000001160220744500201275ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/main/000077500000000000000000000000001160220744500210535ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/main/java/000077500000000000000000000000001160220744500217745ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/000077500000000000000000000000001160220744500225635ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/000077500000000000000000000000001160220744500237115ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/000077500000000000000000000000001160220744500252115ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/000077500000000000000000000000001160220744500266505ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/main/java/org/jvnet/hudson/reactor/Executable.java000066400000000000000000000033061160220744500315760ustar00rootroot00000000000000/* * 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.java000066400000000000000000000024641160220744500314600ustar00rootroot00000000000000/* * 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.java000066400000000000000000000040711160220744500322760ustar00rootroot00000000000000/* * 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.java000066400000000000000000000206371160220744500311220ustar00rootroot00000000000000/* * 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 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 _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.java000066400000000000000000000026361160220744500330000ustar00rootroot00000000000000/* * 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.java000066400000000000000000000074141160220744500326260ustar00rootroot00000000000000/* * 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.java000066400000000000000000000044721160220744500304240ustar00rootroot00000000000000/* * 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 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 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.java000066400000000000000000000054521160220744500317320ustar00rootroot00000000000000/* * 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 discoverTasks(Reactor reactor) throws IOException; /** * Creates a {@link TaskBuilder} that always discovers the given set of tasks. */ public static TaskBuilder fromTasks(final Collection tasks) { return new TaskBuilder() { public Iterable discoverTasks(Reactor reactor) throws IOException { return tasks; } }; } public static TaskBuilder union(final Iterable builders) { return new TaskBuilder() { public Iterable 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.java000066400000000000000000000145151160220744500327140ustar00rootroot00000000000000/* * 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 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 m); /** * Designates that the execution of this task contributes to the given milestone. */ Handle attains(Milestone m); Handle attains(Collection 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 ms) { for (Milestone m : ms) requires(m); return this; } public Handle attains(Milestone m) { attains.add(m); return this; } public Handle attains(Collection 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.java000066400000000000000000000025011160220744500326350ustar00rootroot00000000000000/* * 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/000077500000000000000000000000001160220744500211065ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/test/java/000077500000000000000000000000001160220744500220275ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/test/java/org/000077500000000000000000000000001160220744500226165ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/test/java/org/jvnet/000077500000000000000000000000001160220744500237445ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/test/java/org/jvnet/hudson/000077500000000000000000000000001160220744500252445ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/test/java/org/jvnet/hudson/reactor/000077500000000000000000000000001160220744500267035ustar00rootroot00000000000000jenkinsci-lib-task-reactor-fb38fe8/src/test/java/org/jvnet/hudson/reactor/SessionTest.java000066400000000000000000000247541160220744500320450ustar00rootroot00000000000000/* * 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; } } }