All Downloads are FREE. Search and download functionalities are using the official Maven repository.

brooklyn.util.task.TaskBuilder Maven / Gradle / Ivy

There is a newer version: 0.7.0-M1
Show newest version
package brooklyn.util.task;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;

import brooklyn.management.Task;
import brooklyn.management.TaskFactory;
import brooklyn.management.TaskQueueingContext;
import brooklyn.util.JavaGroovyEquivalents;
import brooklyn.util.collections.MutableMap;

/** Convenience for creating tasks; note that DynamicSequentialTask is the default */
public class TaskBuilder {

    String name = null;
    Callable body = null;
    List> children = new ArrayList>();
    Set tags = new LinkedHashSet();
    Boolean dynamic = null;
    boolean parallel = false;
    
    public static  TaskBuilder builder() {
        return new TaskBuilder();
    }
    
    public TaskBuilder name(String name) {
        this.name = name;
        return this;
    }
    
    /** whether task that is built has been explicitly specified to be a dynamic task 
     * (ie a Task which is also a {@link TaskQueueingContext}
     * whereby new tasks can be added after creation */
    public TaskBuilder dynamic(boolean dynamic) {
        this.dynamic = dynamic;
        return this;
    }
    
    /** whether task that is built should be parallel; cannot (currently) also be dynamic */
    public TaskBuilder parallel(boolean parallel) {
        this.parallel = parallel;
        return this;
    }
    
    public TaskBuilder body(Callable body) {
        this.body = body;
        return this;
    }
    
    public TaskBuilder body(Runnable body) {
        this.body = JavaGroovyEquivalents.toCallable(body);
        return this;
    }

    /** adds a child to the given task; the semantics of how the child is executed is set using
     * {@link #dynamic(boolean)} and {@link #parallel(boolean)} */
    public TaskBuilder add(Task child) {
        children.add(child);
        return this;
    }

    /** adds a tag to the given task */
    public TaskBuilder tag(Object tag) {
        tags.add(tag);
        return this;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Task build() {
        MutableMap flags = MutableMap.of();
        if (name!=null) flags.add("displayName", name);
        if (!tags.isEmpty()) flags.add("tags", tags);
        
        if (dynamic==Boolean.FALSE && children.isEmpty())
            return new BasicTask(flags, body);
        
        // prefer dynamic set unless (a) user has said not dynamic, or (b) it's parallel (since there is no dynamic parallel yet)
        // dynamic has better cancel (will interrupt the thread) and callers can submit tasks flexibly;
        // however dynamic uses an extra thread and task and is noisy for contexts which don't need it
        if (dynamic==Boolean.TRUE || (dynamic==null && !parallel)) {
            if (parallel)
                throw new UnsupportedOperationException("No implementation of parallel dynamic aggregate task available");
            DynamicSequentialTask result = new DynamicSequentialTask(flags, body);
            for (Task t: children)
                result.queue(t);
            return result;
        }
        
        // T must be of type List for these to be valid
        if (body != null) {
            throw new UnsupportedOperationException("No implementation of non-dynamic task with both body and children");
        }
        
        if (parallel)
            return new ParallelTask(flags, children);
        else
            return new SequentialTask(flags, children);
    }

    /** returns a a factory based on this builder */
    public TaskFactory> buildFactory() {
        return new TaskFactory>() {
            public Task newTask() {
                return build();
            }
        };
    }
    
    @Override
    public String toString() {
        return super.toString()+"["+name+"]";
    }
}