/* * Copyright 2012 Jason Miller * * 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. */ package jj.execution; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; /** * Simply a way to attach a task to be executed at the end of another task. * * @author jason * */ public class Promise { private TaskRunner taskRunner; private final AtomicBoolean done = new AtomicBoolean(); private final AtomicReference<List<JJTask<?>>> next = new AtomicReference<>(); Promise() {} Promise taskRunner(final TaskRunner taskRunner) { this.taskRunner = taskRunner; return this; } /** * <p> * Ensures that the next task will get scheduled once the promised task * is finished running, regardless of success or error. no provision is * planned to share any information, so tasks are expected to coordinate * amongst themselves, unless some pattern becomes evident * * <p> * note that chaining calls currently means you are setting up tasks in sequence, * so that<pre class="brush:java"> * execute(task1).then(task2).then(task3); * </pre> * means that task2 starts when task1 finishes, and task3 starts when task2 is done */ public Promise then(final JJTask<?> task) { next().add(task); // if i'm considering this correctly - by allowing the task to get added to the list // and then checking for the latch to be broken, i've established a happens-before // relationship that guarantees that if i then execute all tasks in the list, it won't // double up if (done.get()) { List<JJTask<?>> tasks = next.getAndSet(null); if (tasks != null) { tasks.forEach(taskRunner::execute); } } return task.promise(); } private List<JJTask<?>> next() { if (next.get() == null) { next.compareAndSet(null, new ArrayList<>(0)); // probably never carrying any } return next.get(); } List<JJTask<?>> done() { done.set(true); return next.getAndSet(null); } }