001/*
002 * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License
003 *
004 *  Permission is hereby granted, free of charge, to any person obtaining
005 *  a copy of this software and associated documentation files (the
006 *  "Software"), to deal in the Software without restriction, including
007 *  without limitation the rights to use, copy, modify, merge, publish,
008 *  distribute, sublicense, and/or sell copies of the Software, and to
009 *  permit persons to whom the Software is furnished to do so, subject to
010 *  the following conditions:
011 *
012 *  The above copyright notice and this permission notice shall be
013 *  included in all copies or substantial portions of the Software.
014 *
015 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
016 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
017 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
018 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
019 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
020 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
021 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
022 */
023
024/*
025 * TaskChain for Minecraft Plugins
026 *
027 * Written by Aikar <aikar@aikar.co>
028 * https://aikar.co
029 * https://starlis.com
030 *
031 * @license MIT
032 */
033
034package co.aikar.taskchain;
035
036import co.aikar.taskchain.TaskChainTasks.*;
037
038import java.util.ArrayList;
039import java.util.Collections;
040import java.util.HashMap;
041import java.util.List;
042import java.util.Map;
043import java.util.Objects;
044import java.util.concurrent.CompletableFuture;
045import java.util.concurrent.ConcurrentLinkedQueue;
046import java.util.concurrent.TimeUnit;
047import java.util.function.BiConsumer;
048import java.util.function.Consumer;
049import java.util.function.Predicate;
050import java.util.stream.Collectors;
051
052
053/**
054 * The Main API class of TaskChain. TaskChain's are created by a {@link TaskChainFactory}
055 */
056@SuppressWarnings({"unused", "FieldAccessedSynchronizedAndUnsynchronized"})
057public class TaskChain <T> {
058    private static final ThreadLocal<TaskChain<?>> currentChain = new ThreadLocal<>();
059
060    private final GameInterface impl;
061    private final TaskChainFactory factory;
062    private final Map<String, Object> taskMap = new HashMap<>(0);
063    private final ConcurrentLinkedQueue<TaskHolder<?,?>> chainQueue = new ConcurrentLinkedQueue<>();
064
065    private int currentActionIndex = 0;
066    private int actionIndex = 0;
067    private boolean executed = false;
068    private boolean async = false;
069    private boolean done = false;
070
071    private Object previous;
072    private TaskHolder<?, ?> currentHolder;
073    private Consumer<Boolean> doneCallback;
074    private BiConsumer<Exception, Task<?, ?>> errorHandler;
075
076    /* ======================================================================================== */
077    TaskChain(TaskChainFactory factory) {
078        this.factory = factory;
079        this.impl = factory.getImplementation();
080    }
081    /* ======================================================================================== */
082    // <editor-fold desc="// API Methods - Getters & Setters">
083    /**
084     * Called in an executing task, get the current action index.
085     * For every action that adds a task to the chain, the action index is increased.
086     *
087     * Useful in error or done handlers to know where you are in the chain when it aborted or threw exception.
088     * @return The current index
089     */
090    public int getCurrentActionIndex() {
091        return currentActionIndex;
092    }
093
094    /**
095     * Changes the done callback handler for this chain
096     * @param doneCallback The handler
097     */
098    @SuppressWarnings("WeakerAccess")
099    public void setDoneCallback(Consumer<Boolean> doneCallback) {
100        this.doneCallback = doneCallback;
101    }
102
103    /**
104     * @return The current error handler or null
105     */
106    public BiConsumer<Exception, Task<?, ?>> getErrorHandler() {
107        return errorHandler;
108    }
109
110    /**
111     * Changes the error handler for this chain
112     * @param errorHandler The error handler
113     */
114    @SuppressWarnings("WeakerAccess")
115    public void setErrorHandler(BiConsumer<Exception, Task<?, ?>> errorHandler) {
116        this.errorHandler = errorHandler;
117    }
118    // </editor-fold>
119    /* ======================================================================================== */
120    // <editor-fold desc="// API Methods - Data Wrappers">
121
122    /**
123     * Creates a data wrapper to return multiple objects from a task
124     */
125    public static <D1, D2> TaskChainDataWrappers.Data2<D1, D2> multi(D1 var1, D2 var2) {
126        return new TaskChainDataWrappers.Data2<>(var1, var2);
127    }
128
129    /**
130     * Creates a data wrapper to return multiple objects from a task
131     */
132    public static <D1, D2, D3> TaskChainDataWrappers.Data3<D1, D2, D3> multi(D1 var1, D2 var2, D3 var3) {
133        return new TaskChainDataWrappers.Data3<>(var1, var2, var3);
134    }
135
136    /**
137     * Creates a data wrapper to return multiple objects from a task
138     */
139    public static <D1, D2, D3, D4> TaskChainDataWrappers.Data4<D1, D2, D3, D4> multi(D1 var1, D2 var2, D3 var3, D4 var4) {
140        return new TaskChainDataWrappers.Data4<>(var1, var2, var3, var4);
141    }
142
143    /**
144     * Creates a data wrapper to return multiple objects from a task
145     */
146    public static <D1, D2, D3, D4, D5> TaskChainDataWrappers.Data5<D1, D2, D3, D4, D5> multi(D1 var1, D2 var2, D3 var3, D4 var4, D5 var5) {
147        return new TaskChainDataWrappers.Data5<>(var1, var2, var3, var4, var5);
148    }
149
150    /**
151     * Creates a data wrapper to return multiple objects from a task
152     */
153    public static <D1, D2, D3, D4, D5, D6> TaskChainDataWrappers.Data6<D1, D2, D3, D4, D5, D6> multi(D1 var1, D2 var2, D3 var3, D4 var4, D5 var5, D6 var6) {
154        return new TaskChainDataWrappers.Data6<>(var1, var2, var3, var4, var5, var6);
155    }
156    // </editor-fold>
157    /* ======================================================================================== */
158
159    // <editor-fold desc="// API Methods - Base">
160    /**
161     * Call to abort execution of the chain. Should be called inside of an executing task.
162     */
163    @SuppressWarnings("WeakerAccess")
164    public static void abort() {
165        TaskChainUtil.sneakyThrows(new AbortChainException());
166    }
167
168    /**
169     * Usable only inside of an executing Task or Chain Error/Done handlers
170     *
171     * Gets the current chain that is executing this Task or Error/Done handler
172     * This method should only be called on the same thread that is executing the method.
173     *
174     * In an AsyncExecutingTask or a FutureTask, You must call this method BEFORE passing control to another thread.
175     */
176    @SuppressWarnings("WeakerAccess")
177    public static TaskChain<?> getCurrentChain() {
178        return currentChain.get();
179    }
180
181    /* ======================================================================================== */
182
183    /**
184     * Allows you to call a callback to insert tasks into the chain without having to break the fluent interface
185     *
186     * Example: Plugin.newChain().sync(some::task).configure(chain -> {
187     *     chain.async(some::foo);
188     *     chain.sync(other::bar);
189     * }).async(other::task).execute();
190     *
191     * @param configure Instance of the current chain.
192     * @return The same chain
193     */
194    public TaskChain<T> configure(Consumer<TaskChain<T>> configure) {
195        configure.accept(this);
196        return this;
197    }
198
199    /**
200     * Checks if the chain has a value saved for the specified key.
201     * @param key Key to check if Task Data has a value for
202     */
203    @SuppressWarnings("WeakerAccess")
204    public boolean hasTaskData(String key) {
205        return taskMap.containsKey(key);
206    }
207
208    /**
209     * Retrieves a value relating to a specific key, saved by a previous task.
210     *
211     * @param key Key to look up Task Data for
212     * @param <R> Type the Task Data value is expected to be
213     */
214    @SuppressWarnings("WeakerAccess")
215    public <R> R getTaskData(String key) {
216        //noinspection unchecked
217        return (R) taskMap.get(key);
218    }
219
220    /**
221     * Saves a value for this chain so that a task furthur up the chain can access it.
222     *
223     * Useful for passing multiple values to the next (or furthur) tasks.
224     *
225     * @param key Key to store in Task Data
226     * @param val Value to store in Task Data
227     * @param <R> Type the Task Data value is expected to be
228     */
229    @SuppressWarnings("WeakerAccess")
230    public <R> R setTaskData(String key, Object val) {
231        //noinspection unchecked
232        return (R) taskMap.put(key, val);
233    }
234
235    /**
236     * Removes a saved value on the chain.
237     *
238     * @param key Key to remove from Task Data
239     * @param <R> Type the Task Data value is expected to be
240     */
241    @SuppressWarnings("WeakerAccess")
242    public <R> R removeTaskData(String key) {
243        //noinspection unchecked
244        return (R) taskMap.remove(key);
245    }
246
247    /**
248     * Takes the previous tasks return value, stores it to the specified key
249     * as Task Data, and then forwards that value to the next task.
250     *
251     * @param key Key to store the previous return value into Task Data
252     */
253    @SuppressWarnings("WeakerAccess")
254    public TaskChain<T> storeAsData(String key) {
255        return current((val) -> {
256            setTaskData(key, val);
257            return val;
258        });
259    }
260
261    /**
262     * Reads the specified key from Task Data, and passes it to the next task.
263     *
264     * Will need to pass expected type such as chain.&lt;Foo&gt;returnData("key")
265     *
266     * @param key Key to retrieve from Task Data and pass to next task
267     * @param <R> Return type that the next parameter can expect as argument type
268     */
269    @SuppressWarnings("WeakerAccess")
270    public <R> TaskChain<R> returnData(String key) {
271        //noinspection unchecked
272        return currentFirst(() -> (R) getTaskData(key));
273    }
274
275    /**
276     * Returns the chain itself to the next task.
277     */
278    @SuppressWarnings("WeakerAccess")
279    public TaskChain<TaskChain<?>> returnChain() {
280        return currentFirst(() -> this);
281    }
282
283
284    /**
285     * IMPLEMENTATION SPECIFIC!!
286     * Consult your application implementation to understand how long 1 unit is.
287     *
288     * For example, in Minecraft it is a tick, which is roughly 50 milliseconds, but not guaranteed.
289     *
290     * Adds a delay to the chain execution.
291     *
292     * @param gameUnits # of game units to delay before next task
293     */
294    @SuppressWarnings("WeakerAccess")
295    public TaskChain<T> delay(final int gameUnits) {
296        //noinspection CodeBlock2Expr
297        return currentCallback((input, next) -> {
298            impl.scheduleTask(gameUnits, () -> next.accept(input));
299        });
300    }
301
302    /**
303     * Adds a real time delay to the chain execution.
304     * Chain will abort if the delay is interrupted.
305     *
306     * @param duration duration of the delay before next task
307     */
308    @SuppressWarnings("WeakerAccess")
309    public TaskChain<T> delay(final int duration, TimeUnit unit) {
310        //noinspection CodeBlock2Expr
311        return currentCallback((input, next) -> {
312            impl.scheduleTask(duration, unit, () -> next.accept(input));
313        });
314    }
315
316    // </editor-fold>
317    // <editor-fold desc="// API Methods - Abort">
318
319    /**
320     * Aborts the chain once this step is reached. This is primarily useful when you are
321     * dynamically building the chains steps (such as .configure()) and want to conditionally stop the
322     * chain from proceeding.
323     *
324     * @return Chain
325     */
326    public TaskChain<?> abortChain() {
327        return current(TaskChain::abort);
328    }
329
330    /**
331     * Checks if the previous task return was null.
332     *
333     * If not null, the previous task return will forward to the next task.
334     */
335    @SuppressWarnings("WeakerAccess")
336    public TaskChain<T> abortIfNull() {
337        return abortIfNull(null, null, null, null);
338    }
339
340    /**
341     * {@link TaskChain#abortIf(Object, TaskChainAbortAction, Object, Object, Object)}
342     */
343    @SuppressWarnings("WeakerAccess")
344    public TaskChain<T> abortIfNull(TaskChainAbortAction<?, ?, ?> action) {
345        return abortIf(Predicate.isEqual(null), action, null, null, null);
346    }
347
348    /**
349     * {@link TaskChain#abortIf(Object, TaskChainAbortAction, Object, Object, Object)}
350     */
351    @SuppressWarnings("WeakerAccess")
352    public <A1> TaskChain<T> abortIfNull(TaskChainAbortAction<A1, ?, ?> action, A1 arg1) {
353        //noinspection unchecked
354        return abortIf(Predicate.isEqual(null), action, arg1, null, null);
355    }
356
357    /**
358     * {@link TaskChain#abortIf(Object, TaskChainAbortAction, Object, Object, Object)}
359     */
360    @SuppressWarnings("WeakerAccess")
361    public <A1, A2> TaskChain<T> abortIfNull(TaskChainAbortAction<A1, A2, ?> action, A1 arg1, A2 arg2) {
362        //noinspection unchecked
363        return abortIf(Predicate.isEqual(null), action, arg1, arg2, null);
364    }
365
366    /**
367     * Checks if the previous task return was null, and aborts if it was
368     * Then executes supplied action handler
369     *
370     * If not null, the previous task return will forward to the next task.
371     */
372    @SuppressWarnings("WeakerAccess")
373    public <A1, A2, A3> TaskChain<T> abortIfNull(TaskChainAbortAction<A1, A2, A3> action, A1 arg1, A2 arg2, A3 arg3) {
374        //noinspection unchecked
375        return abortIf(Predicate.isEqual(null), action, arg1, arg2, arg3);
376    }
377
378    /**
379     * Checks if the previous task return is the supplied value.
380     *
381     * If not, the previous task return will forward to the next task.
382     */
383    @SuppressWarnings("WeakerAccess")
384    public TaskChain<T> abortIf(T ifObj) {
385        return abortIf(ifObj, null, null, null, null);
386    }
387
388    /**
389     * {@link TaskChain#abortIf(Object, TaskChainAbortAction, Object, Object, Object)}
390     */
391    @SuppressWarnings("WeakerAccess")
392    public TaskChain<T> abortIf(T ifObj, TaskChainAbortAction<?, ?, ?> action) {
393        return abortIf(ifObj, action, null, null, null);
394    }
395
396    /**
397     * {@link TaskChain#abortIf(Object, TaskChainAbortAction, Object, Object, Object)}
398     */
399    @SuppressWarnings("WeakerAccess")
400    public <A1> TaskChain<T> abortIf(T ifObj, TaskChainAbortAction<A1, ?, ?> action, A1 arg1) {
401        return abortIf(ifObj, action, arg1, null, null);
402    }
403
404    /**
405     * {@link TaskChain#abortIf(Object, TaskChainAbortAction, Object, Object, Object)}
406     */
407    @SuppressWarnings("WeakerAccess")
408    public <A1, A2> TaskChain<T> abortIf(T ifObj, TaskChainAbortAction<A1, A2, ?> action, A1 arg1, A2 arg2) {
409        return abortIf(ifObj, action, arg1, arg2, null);
410    }
411
412    /**
413     * {@link TaskChain#abortIf(Predicate, TaskChainAbortAction, Object, Object, Object)}
414     */
415    @SuppressWarnings("WeakerAccess")
416    public <A1, A2, A3> TaskChain<T> abortIf(T ifObj, TaskChainAbortAction<A1, A2, A3> action, A1 arg1, A2 arg2, A3 arg3) {
417        return abortIf(Predicate.isEqual(ifObj), action, arg1, arg2, arg3);
418    }
419    
420    /**
421     * Checks if the previous task return matches the supplied predicate, and aborts if it was.
422     * 
423     * If predicate does not match, the previous task return will forward to the next task.
424     */
425    @SuppressWarnings("WeakerAccess")
426    public TaskChain<T> abortIf(Predicate<T> predicate) {
427        return abortIf(predicate, null, null, null, null);
428    }
429
430    /**
431     * {@link TaskChain#abortIf(Object, TaskChainAbortAction, Object, Object, Object)}
432     */
433    @SuppressWarnings("WeakerAccess")
434    public TaskChain<T> abortIf(Predicate<T> predicate, TaskChainAbortAction<?, ?, ?> action) {
435        return abortIf(predicate, action, null, null, null);
436    }
437
438    /**
439     * {@link TaskChain#abortIf(Object, TaskChainAbortAction, Object, Object, Object)}
440     */
441    @SuppressWarnings("WeakerAccess")
442    public <A1> TaskChain<T> abortIf(Predicate<T> predicate, TaskChainAbortAction<A1, ?, ?> action, A1 arg1) {
443        return abortIf(predicate, action, arg1, null, null);
444    }
445
446    /**
447     * {@link TaskChain#abortIf(Object, TaskChainAbortAction, Object, Object, Object)}
448     */
449    @SuppressWarnings("WeakerAccess")
450    public <A1, A2> TaskChain<T> abortIf(Predicate<T> predicate, TaskChainAbortAction<A1, A2, ?> action, A1 arg1, A2 arg2) {
451        return abortIf(predicate, action, arg1, arg2, null);
452    }
453
454    /**
455     * Checks if the previous task return matches the supplied predicate, and aborts if it was.
456     * Then executes supplied action handler
457     * 
458     * If predicate does not match, the previous task return will forward to the next task.
459     */
460    public <A1, A2, A3> TaskChain<T> abortIf(Predicate<T> predicate, TaskChainAbortAction<A1, A2, A3> action, A1 arg1, A2 arg2, A3 arg3) {
461        return current((obj) -> {
462           if (predicate.test(obj)) {
463               handleAbortAction(action, arg1, arg2, arg3);
464               return null;
465           }
466           return obj;
467        });
468    }
469
470    /**
471     * {@link TaskChain#abortIfNot(Object, TaskChainAbortAction, Object, Object, Object)}
472     */
473    @SuppressWarnings("WeakerAccess")
474    public TaskChain<T> abortIfNot(T ifNotObj) {
475        return abortIfNot(ifNotObj, null, null, null, null);
476    }
477
478    /**
479     * {@link TaskChain#abortIfNot(Object, TaskChainAbortAction, Object, Object, Object)}
480     */
481    @SuppressWarnings("WeakerAccess")
482    public TaskChain<T> abortIfNot(T ifNotObj, TaskChainAbortAction<?, ?, ?> action) {
483        return abortIfNot(ifNotObj, action, null, null, null);
484    }
485
486    /**
487     * {@link TaskChain#abortIfNot(Object, TaskChainAbortAction, Object, Object, Object)}
488     */
489    @SuppressWarnings("WeakerAccess")
490    public <A1> TaskChain<T> abortIfNot(T ifNotObj, TaskChainAbortAction<A1, ?, ?> action, A1 arg1) {
491        return abortIfNot(ifNotObj, action, arg1, null, null);
492    }
493
494    /**
495     * {@link TaskChain#abortIfNot(Object, TaskChainAbortAction, Object, Object, Object)}
496     */
497    @SuppressWarnings("WeakerAccess")
498    public <A1, A2> TaskChain<T> abortIfNot(T ifNotObj, TaskChainAbortAction<A1, A2, ?> action, A1 arg1, A2 arg2) {
499        return abortIfNot(ifNotObj, action, arg1, arg2, null);
500    }
501
502    /**
503     * {@link TaskChain#abortIfNot(Predicate, TaskChainAbortAction, Object, Object, Object)}
504     */
505    @SuppressWarnings("WeakerAccess")
506    public <A1, A2, A3> TaskChain<T> abortIfNot(T ifNotObj, TaskChainAbortAction<A1, A2, A3> action, A1 arg1, A2 arg2, A3 arg3) {
507        return abortIfNot(Predicate.<T>isEqual(ifNotObj), action, arg1, arg2, arg3);
508    }
509    
510    /**
511     * Checks if the previous task return does NOT match the supplied predicate, and aborts if it does not match.
512     * 
513     * If predicate matches, the previous task return will forward to the next task.
514     */
515    @SuppressWarnings("WeakerAccess")
516    public TaskChain<T> abortIfNot(Predicate<T> ifNotPredicate) {
517        return abortIfNot(ifNotPredicate, null, null, null, null);
518    }
519
520    /**
521     * {@link TaskChain#abortIfNot(Object, TaskChainAbortAction, Object, Object, Object)}
522     */
523    @SuppressWarnings("WeakerAccess")
524    public TaskChain<T> abortIfNot(Predicate<T> ifNotPredicate, TaskChainAbortAction<?, ?, ?> action) {
525        return abortIfNot(ifNotPredicate, action, null, null, null);
526    }
527
528    /**
529     * {@link TaskChain#abortIfNot(Object, TaskChainAbortAction, Object, Object, Object)}
530     */
531    @SuppressWarnings("WeakerAccess")
532    public <A1> TaskChain<T> abortIfNot(Predicate<T> ifNotPredicate, TaskChainAbortAction<A1, ?, ?> action, A1 arg1) {
533        return abortIfNot(ifNotPredicate, action, arg1, null, null);
534    }
535
536    /**
537     * {@link TaskChain#abortIfNot(Object, TaskChainAbortAction, Object, Object, Object)}
538     */
539    @SuppressWarnings("WeakerAccess")
540    public <A1, A2> TaskChain<T> abortIfNot(Predicate<T> ifNotPredicate, TaskChainAbortAction<A1, A2, ?> action, A1 arg1, A2 arg2) {
541        return abortIfNot(ifNotPredicate, action, arg1, arg2, null);
542    }
543
544    /**
545     * Checks if the previous task return does NOT match the supplied predicate, and aborts if it does not match.
546     * Then executes supplied action handler
547     * 
548     * If predicate matches, the previous task return will forward to the next task.
549     */
550    @SuppressWarnings("WeakerAccess")
551    public <A1, A2, A3> TaskChain<T> abortIfNot(Predicate<T> ifNotPredicate, TaskChainAbortAction<A1, A2, A3> action, A1 arg1, A2 arg2, A3 arg3) {
552        return abortIf(ifNotPredicate.negate(), action, arg1, arg2, arg3);
553    }
554
555    // </editor-fold>
556    // <editor-fold desc="// API Methods - Async Executing">
557    /* ======================================================================================== */
558    // Async Executing Tasks
559    /* ======================================================================================== */
560
561    /**
562     * Execute a task on the main thread, with no previous input, and a callback to return the response to.
563     *
564     * It's important you don't perform blocking operations in this method. Only use this if
565     * the task will be scheduling a different sync operation outside of the TaskChains scope.
566     *
567     * Usually you could achieve the same design with a blocking API by switching to an async task
568     * for the next task and running it there.
569     *
570     * This method would primarily be for cases where you need to use an API that ONLY provides
571     * a callback style API.
572     *
573     * @param task The task to execute
574     * @param <R> Return type that the next parameter can expect as argument type
575     */
576    @SuppressWarnings("WeakerAccess")
577    public <R> TaskChain<R> syncFirstCallback(AsyncExecutingFirstTask<R> task) {
578        //noinspection unchecked
579        return add0(new TaskHolder<>(this, false, task));
580    }
581
582    /**
583     * {@link TaskChain#syncFirstCallback(AsyncExecutingFirstTask)} but ran off main thread
584     * @param task The task to execute
585     * @param <R> Return type that the next parameter can expect as argument type
586     */
587    @SuppressWarnings("WeakerAccess")
588    public <R> TaskChain<R> asyncFirstCallback(AsyncExecutingFirstTask<R> task) {
589        //noinspection unchecked
590        return add0(new TaskHolder<>(this, true, task));
591    }
592
593    /**
594     * {@link TaskChain#syncFirstCallback(AsyncExecutingFirstTask)} but ran on current thread the Chain was created on
595     * @param task The task to execute
596     * @param <R> Return type that the next parameter can expect as argument type
597     */
598    @SuppressWarnings("WeakerAccess")
599    public <R> TaskChain<R> currentFirstCallback(AsyncExecutingFirstTask<R> task) {
600        //noinspection unchecked
601        return add0(new TaskHolder<>(this, null, task));
602    }
603
604    /**
605     * Execute a task on the main thread, with the last output, and a callback to return the response to.
606     *
607     * It's important you don't perform blocking operations in this method. Only use this if
608     * the task will be scheduling a different sync operation outside of the TaskChains scope.
609     *
610     * Usually you could achieve the same design with a blocking API by switching to an async task
611     * for the next task and running it there.
612     *
613     * This method would primarily be for cases where you need to use an API that ONLY provides
614     * a callback style API.
615     *
616     * @param task The task to execute
617     * @param <R> Return type that the next parameter can expect as argument type
618     */
619    @SuppressWarnings("WeakerAccess")
620    public <R> TaskChain<R> syncCallback(AsyncExecutingTask<R, T> task) {
621        //noinspection unchecked
622        return add0(new TaskHolder<>(this, false, task));
623    }
624
625    /**
626     * {@link TaskChain#syncCallback(AsyncExecutingTask)}, ran on main thread but no input or output
627     * @param task The task to execute
628     */
629    @SuppressWarnings("WeakerAccess")
630    public TaskChain<?> syncCallback(AsyncExecutingGenericTask task) {
631        return add0(new TaskHolder<>(this, false, task));
632    }
633
634    /**
635     * {@link TaskChain#syncCallback(AsyncExecutingTask)} but ran off main thread
636     * @param task The task to execute
637     * @param <R> Return type that the next parameter can expect as argument type
638     */
639    @SuppressWarnings("WeakerAccess")
640    public <R> TaskChain<R> asyncCallback(AsyncExecutingTask<R, T> task) {
641        //noinspection unchecked
642        return add0(new TaskHolder<>(this, true, task));
643    }
644
645    /**
646     * {@link TaskChain#syncCallback(AsyncExecutingTask)} but ran off main thread
647     * @param task The task to execute
648     */
649    @SuppressWarnings("WeakerAccess")
650    public TaskChain<?> asyncCallback(AsyncExecutingGenericTask task) {
651        return add0(new TaskHolder<>(this, true, task));
652    }
653
654    /**
655     * {@link TaskChain#syncCallback(AsyncExecutingTask)} but ran on current thread the Chain was created on
656     * @param task The task to execute
657     * @param <R> Return type that the next parameter can expect as argument type
658     */
659    @SuppressWarnings("WeakerAccess")
660    public <R> TaskChain<R> currentCallback(AsyncExecutingTask<R, T> task) {
661        //noinspection unchecked
662        return add0(new TaskHolder<>(this, null, task));
663    }
664
665    /**
666     * {@link TaskChain#syncCallback(AsyncExecutingTask)} but ran on current thread the Chain was created on
667     * @param task The task to execute
668     */
669    @SuppressWarnings("WeakerAccess")
670    public TaskChain<?> currentCallback(AsyncExecutingGenericTask task) {
671        return add0(new TaskHolder<>(this, null, task));
672    }
673
674    // </editor-fold>
675    // <editor-fold desc="// API Methods - Future">
676    /* ======================================================================================== */
677    // Future Tasks
678    /* ======================================================================================== */
679
680    /**
681     * Takes a supplied Future, and holds processing of the chain until the future completes.
682     * The value of the Future will be passed until the next task.
683     *
684     * @param future The Future to wait until it is complete on
685     * @param <R> Return type that the next parameter can expect as argument type
686     */
687    @SuppressWarnings("WeakerAccess")
688    public <R> TaskChain<R> future(CompletableFuture<R> future) {
689        return currentFuture((input) -> future);
690    }
691
692    /**
693     * Takes multiple supplied Futures, and holds processing of the chain until the futures completes.
694     * The results of the Futures will be passed until the next task.
695     *
696     * @param futures The Futures to wait until it is complete on
697     * @param <R> Return type that the next parameter can expect as argument type
698     */
699    @SafeVarargs
700    @SuppressWarnings("WeakerAccess")
701    public final <R> TaskChain<List<R>> futures(CompletableFuture<R>... futures) {
702        List<CompletableFuture<R>> futureList = new ArrayList<>(futures.length);
703        Collections.addAll(futureList, futures);
704        return futures(futureList);
705    }
706
707    /**
708     * Takes multiple supplied Futures, and holds processing of the chain until the futures completes.
709     * The results of the Futures will be passed until the next task.
710     *
711     * @param futures The Futures to wait until it is complete on
712     * @param <R> Return type that the next parameter can expect as argument type
713     */
714    @SuppressWarnings("WeakerAccess")
715    public <R> TaskChain<List<R>> futures(List<CompletableFuture<R>> futures) {
716        return currentFuture((input) -> getFuture(futures));
717    }
718
719    /**
720     * Executes a Task on the Main thread that provides a list of Futures, and holds processing
721     * of the chain until all of the futures completes.
722     *
723     * The response of every future will be passed to the next task as a List, in the order
724     * the futures were supplied.
725     *
726     * @param task The Futures Provider Task
727     * @param <R> Return type that the next parameter can expect as argument type
728     */
729    @SuppressWarnings("WeakerAccess")
730    public <R> TaskChain<List<R>> syncFutures(Task<List<CompletableFuture<R>>, T> task) {
731        return syncFuture((input) -> getFuture(task.run(input)));
732    }
733
734    /**
735     * Executes a Task off the Main thread that provides a list of Futures, and holds processing
736     * of the chain until all of the futures completes.
737     *
738     * The response of every future will be passed to the next task as a List, in the order
739     * the futures were supplied.
740     *
741     * @param task The Futures Provider Task
742     * @param <R> Return type that the next parameter can expect as argument type
743     */
744    @SuppressWarnings("WeakerAccess")
745    public <R> TaskChain<List<R>> asyncFutures(Task<List<CompletableFuture<R>>, T> task) {
746        return asyncFuture((input) -> getFuture(task.run(input)));
747    }
748
749    /**
750     * Executes a Task on the current thread that provides a list of Futures, and holds processing
751     * of the chain until all of the futures completes.
752     *
753     * The response of every future will be passed to the next task as a List, in the order
754     * the futures were supplied.
755     *
756     * @param task The Futures Provider Task
757     * @param <R> Return type that the next parameter can expect as argument type
758     */
759    @SuppressWarnings("WeakerAccess")
760    public <R> TaskChain<List<R>> currentFutures(Task<List<CompletableFuture<R>>, T> task) {
761        return currentFuture((input) -> getFuture(task.run(input)));
762    }
763
764    /**
765     * Executes a Task on the Main thread that provides a list of Futures, and holds processing
766     * of the chain until all of the futures completes.
767     *
768     * The response of every future will be passed to the next task as a List, in the order
769     * the futures were supplied.
770     *
771     * @param task The Futures Provider Task
772     * @param <R> Return type that the next parameter can expect as argument type
773     */
774    @SuppressWarnings("WeakerAccess")
775    public <R> TaskChain<List<R>> syncFirstFutures(FirstTask<List<CompletableFuture<R>>> task) {
776        return syncFuture((input) -> getFuture(task.run()));
777    }
778
779    /**
780     * Executes a Task off the Main thread that provides a list of Futures, and holds processing
781     * of the chain until all of the futures completes.
782     *
783     * The response of every future will be passed to the next task as a List, in the order
784     * the futures were supplied.
785     *
786     * @param task The Futures Provider Task
787     * @param <R> Return type that the next parameter can expect as argument type
788     */
789    @SuppressWarnings("WeakerAccess")
790    public <R> TaskChain<List<R>> asyncFirstFutures(FirstTask<List<CompletableFuture<R>>> task) {
791        return asyncFuture((input) -> getFuture(task.run()));
792    }
793
794    /**
795     * Executes a Task on the current thread that provides a list of Futures, and holds processing
796     * of the chain until all of the futures completes.
797     *
798     * The response of every future will be passed to the next task as a List, in the order
799     * the futures were supplied.
800     *
801     * @param task The Futures Provider Task
802     * @param <R> Return type that the next parameter can expect as argument type
803     */
804    @SuppressWarnings("WeakerAccess")
805    public <R> TaskChain<List<R>> currentFirstFutures(FirstTask<List<CompletableFuture<R>>> task) {
806        return currentFuture((input) -> getFuture(task.run()));
807    }
808
809    /**
810     * Execute a task on the main thread, with no previous input, that will return a Future to signal completion
811     *
812     * It's important you don't perform blocking operations in this method. Only use this if
813     * the task will be scheduling a different async operation outside of the TaskChains scope.
814     *
815     *
816     * @param task The task to execute
817     * @param <R> Return type that the next parameter can expect as argument type
818     */
819    @SuppressWarnings("WeakerAccess")
820    public <R> TaskChain<R> syncFirstFuture(FutureFirstTask<R> task) {
821        //noinspection unchecked
822        return add0(new TaskHolder<>(this, false, task));
823    }
824
825    /**
826     * {@link TaskChain#syncFirstFuture(FutureFirstTask)} but ran off main thread
827     * @param task The task to execute
828     * @param <R> Return type that the next parameter can expect as argument type
829     */
830    @SuppressWarnings("WeakerAccess")
831    public <R> TaskChain<R> asyncFirstFuture(FutureFirstTask<R> task) {
832        //noinspection unchecked
833        return add0(new TaskHolder<>(this, true, task));
834    }
835
836    /**
837     * {@link TaskChain#syncFirstFuture(FutureFirstTask)} but ran on current thread the Chain was created on
838     * @param task The task to execute
839     * @param <R> Return type that the next parameter can expect as argument type
840     */
841    @SuppressWarnings("WeakerAccess")
842    public <R> TaskChain<R> currentFirstFuture(FutureFirstTask<R> task) {
843        //noinspection unchecked
844        return add0(new TaskHolder<>(this, null, task));
845    }
846
847    /**
848     * Execute a task on the main thread, with the last output as the input to the future provider,
849     * that will return a Future to signal completion.
850     *
851     * It's important you don't perform blocking operations in this method. Only use this if
852     * the task will be scheduling a different async operation outside of the TaskChains scope.
853     *
854     * @param task The task to execute
855     * @param <R> Return type that the next parameter can expect as argument type
856     */
857    @SuppressWarnings("WeakerAccess")
858    public <R> TaskChain<R> syncFuture(FutureTask<R, T> task) {
859        //noinspection unchecked
860        return add0(new TaskHolder<>(this, false, task));
861    }
862
863    /**
864     * {@link TaskChain#syncFuture(FutureTask)}, ran on main thread but no input or output
865     * @param task The task to execute
866     */
867    @SuppressWarnings("WeakerAccess")
868    public TaskChain<?> syncFuture(FutureGenericTask task) {
869        return add0(new TaskHolder<>(this, false, task));
870    }
871
872    /**
873     * {@link TaskChain#syncFuture(FutureTask)} but the future provider is ran off main thread
874     * @param task The task to execute
875     * @param <R> Return type that the next parameter can expect as argument type
876     */
877    @SuppressWarnings("WeakerAccess")
878    public <R> TaskChain<R> asyncFuture(FutureTask<R, T> task) {
879        //noinspection unchecked
880        return add0(new TaskHolder<>(this, true, task));
881    }
882
883    /**
884     * {@link TaskChain#syncFuture(FutureTask)} but the future provider is ran off main thread
885     * @param task The task to execute
886     */
887    @SuppressWarnings("WeakerAccess")
888    public TaskChain<?> asyncFuture(FutureGenericTask task) {
889        return add0(new TaskHolder<>(this, true, task));
890    }
891
892    /**
893     * {@link TaskChain#syncFuture(FutureTask)} but the future provider is ran on current thread the Chain was created on
894     * @param task The task to execute
895     * @param <R> Return type that the next parameter can expect as argument type
896     */
897    @SuppressWarnings("WeakerAccess")
898    public <R> TaskChain<R> currentFuture(FutureTask<R, T> task) {
899        //noinspection unchecked
900        return add0(new TaskHolder<>(this, null, task));
901    }
902
903    /**
904     * {@link TaskChain#syncFuture(FutureTask)} but the future provider is ran on current thread the Chain was created on
905     * @param task The task to execute
906     */
907    @SuppressWarnings("WeakerAccess")
908    public TaskChain<?> currentFuture(FutureGenericTask task) {
909        return add0(new TaskHolder<>(this, null, task));
910    }
911
912    // </editor-fold>
913    // <editor-fold desc="// API Methods - Normal">
914    /* ======================================================================================== */
915    // Normal Tasks
916    /* ======================================================================================== */
917
918    /**
919     * Execute task on main thread, with no input, returning an output
920     * @param task The task to execute
921     * @param <R> Return type that the next parameter can expect as argument type
922     */
923    @SuppressWarnings("WeakerAccess")
924    public <R> TaskChain<R> syncFirst(FirstTask<R> task) {
925        //noinspection unchecked
926        return add0(new TaskHolder<>(this, false, task));
927    }
928
929    /**
930     * {@link TaskChain#syncFirst(FirstTask)} but ran off main thread
931     * @param task The task to execute
932     * @param <R> Return type that the next parameter can expect as argument type
933     */
934    @SuppressWarnings("WeakerAccess")
935    public <R> TaskChain<R> asyncFirst(FirstTask<R> task) {
936        //noinspection unchecked
937        return add0(new TaskHolder<>(this, true, task));
938    }
939
940    /**
941     * {@link TaskChain#syncFirst(FirstTask)} but ran on current thread the Chain was created on
942     * @param task The task to execute
943     * @param <R> Return type that the next parameter can expect as argument type
944     */
945    @SuppressWarnings("WeakerAccess")
946    public <R> TaskChain<R> currentFirst(FirstTask<R> task) {
947        //noinspection unchecked
948        return add0(new TaskHolder<>(this, null, task));
949    }
950
951    /**
952     * Execute task on main thread, with the last returned input, returning an output
953     * @param task The task to execute
954     * @param <R> Return type that the next parameter can expect as argument type
955     */
956    @SuppressWarnings("WeakerAccess")
957    public <R> TaskChain<R> sync(Task<R, T> task) {
958        //noinspection unchecked
959        return add0(new TaskHolder<>(this, false, task));
960    }
961
962    /**
963     * Execute task on main thread, with no input or output
964     * @param task The task to execute
965     */
966    @SuppressWarnings("WeakerAccess")
967    public TaskChain<?> sync(GenericTask task) {
968        return add0(new TaskHolder<>(this, false, task));
969    }
970
971    /**
972     * {@link TaskChain#sync(Task)} but ran off main thread
973     * @param task The task to execute
974     * @param <R> Return type that the next parameter can expect as argument type
975     */
976    @SuppressWarnings("WeakerAccess")
977    public <R> TaskChain<R> async(Task<R, T> task) {
978        //noinspection unchecked
979        return add0(new TaskHolder<>(this, true, task));
980    }
981
982    /**
983     * {@link TaskChain#sync(GenericTask)} but ran off main thread
984     * @param task The task to execute
985     */
986    @SuppressWarnings("WeakerAccess")
987    public TaskChain<?> async(GenericTask task) {
988        return add0(new TaskHolder<>(this, true, task));
989    }
990
991    /**
992     * {@link TaskChain#sync(Task)} but ran on current thread the Chain was created on
993     * @param task The task to execute
994     * @param <R> Return type that the next parameter can expect as argument type
995     */
996    @SuppressWarnings("WeakerAccess")
997    public <R> TaskChain<R> current(Task<R, T> task) {
998        //noinspection unchecked
999        return add0(new TaskHolder<>(this, null, task));
1000    }
1001
1002    /**
1003     * {@link TaskChain#sync(GenericTask)} but ran on current thread the Chain was created on
1004     * @param task The task to execute
1005     */
1006    @SuppressWarnings("WeakerAccess")
1007    public TaskChain<?> current(GenericTask task) {
1008        return add0(new TaskHolder<>(this, null, task));
1009    }
1010
1011
1012    /**
1013     * Execute task on main thread, with the last output, and no furthur output
1014     * @param task The task to execute
1015     */
1016    @SuppressWarnings("WeakerAccess")
1017    public TaskChain<?> syncLast(LastTask<T> task) {
1018        return add0(new TaskHolder<>(this, false, task));
1019    }
1020
1021    /**
1022     * {@link TaskChain#syncLast(LastTask)} but ran off main thread
1023     * @param task The task to execute
1024     */
1025    @SuppressWarnings("WeakerAccess")
1026    public TaskChain<?> asyncLast(LastTask<T> task) {
1027        return add0(new TaskHolder<>(this, true, task));
1028    }
1029
1030    /**
1031     * {@link TaskChain#syncLast(LastTask)} but ran on current thread the Chain was created on
1032     * @param task The task to execute
1033     */
1034    @SuppressWarnings("WeakerAccess")
1035    public TaskChain<?> currentLast(LastTask<T> task) {
1036        return add0(new TaskHolder<>(this, null, task));
1037    }
1038
1039    /**
1040     * Finished adding tasks, begins executing them.
1041     */
1042    @SuppressWarnings("WeakerAccess")
1043    public void execute() {
1044        execute((Consumer<Boolean>) null, null);
1045    }
1046
1047    /**
1048     * Finished adding tasks, begins executing them with a done notifier
1049     * @param done The Callback to handle when the chain has finished completion. Argument to consumer contains finish state
1050     */
1051    @SuppressWarnings("WeakerAccess")
1052    public void execute(Runnable done) {
1053        execute((finished) -> done.run(), null);
1054    }
1055
1056    /**
1057     * Finished adding tasks, begins executing them with a done notifier and error handler
1058     * @param done The Callback to handle when the chain has finished completion. Argument to consumer contains finish state
1059     * @param errorHandler The Error handler to handle exceptions
1060     */
1061    @SuppressWarnings("WeakerAccess")
1062    public void execute(Runnable done, BiConsumer<Exception, Task<?, ?>> errorHandler) {
1063        execute((finished) -> done.run(), errorHandler);
1064    }
1065
1066    /**
1067     * Finished adding tasks, with a done notifier
1068     * @param done The Callback to handle when the chain has finished completion. Argument to consumer contains finish state
1069     */
1070    @SuppressWarnings("WeakerAccess")
1071    public void execute(Consumer<Boolean> done) {
1072        execute(done, null);
1073    }
1074
1075    /**
1076     * Finished adding tasks, begins executing them, with an error handler
1077     * @param errorHandler The Error handler to handle exceptions
1078     */
1079    public void execute(BiConsumer<Exception, Task<?, ?>> errorHandler) {
1080        execute((Consumer<Boolean>) null, errorHandler);
1081    }
1082
1083    /**
1084     * Finished adding tasks, begins executing them with a done notifier and error handler
1085     * @param done The Callback to handle when the chain has finished completion. Argument to consumer contains finish state
1086     * @param errorHandler The Error handler to handle exceptions
1087     */
1088    public void execute(Consumer<Boolean> done, BiConsumer<Exception, Task<?, ?>> errorHandler) {
1089        if (errorHandler == null) {
1090            errorHandler = factory.getDefaultErrorHandler();
1091        }
1092        this.doneCallback = done;
1093        this.errorHandler = errorHandler;
1094        execute0();
1095    }
1096
1097    // </editor-fold>
1098    /* ======================================================================================== */
1099    // <editor-fold desc="// Implementation Details">
1100    private <A1, A2, A3> void handleAbortAction(TaskChainAbortAction<A1, A2, A3> action, A1 arg1, A2 arg2, A3 arg3) {
1101        if (action != null) {
1102            final TaskChain<?> prev = currentChain.get();
1103            try {
1104                currentChain.set(this);
1105                action.onAbort(this, arg1, arg2, arg3);
1106            } catch (Exception e) {
1107                TaskChainUtil.logError("TaskChain Exception in Abort Action handler: " + action.getClass().getName());
1108                TaskChainUtil.logError("Current Action Index was: " + currentActionIndex);
1109                e.printStackTrace();
1110            } finally {
1111                currentChain.set(prev);
1112            }
1113        }
1114        abort();
1115    }
1116
1117    void execute0() {
1118        synchronized (this) {
1119            if (this.executed) {
1120                throw new RuntimeException("Already executed");
1121            }
1122            this.executed = true;
1123        }
1124        async = !impl.isMainThread();
1125        nextTask();
1126    }
1127
1128    void done(boolean finished) {
1129        this.done = true;
1130        if (this.doneCallback != null) {
1131            final TaskChain<?> prev = currentChain.get();
1132            try {
1133                currentChain.set(this);
1134                this.doneCallback.accept(finished);
1135            } catch (Exception e) {
1136                this.handleError(e, null);
1137            } finally {
1138                currentChain.set(prev);
1139            }
1140        }
1141    }
1142
1143    @SuppressWarnings({"rawtypes", "WeakerAccess"})
1144    protected TaskChain add0(TaskHolder<?,?> task) {
1145        synchronized (this) {
1146            if (this.executed) {
1147                throw new RuntimeException("TaskChain is executing");
1148            }
1149        }
1150
1151        this.chainQueue.add(task);
1152        return this;
1153    }
1154
1155    /**
1156     * Fires off the next task, and switches between Async/Sync as necessary.
1157     */
1158    private void nextTask() {
1159        synchronized (this) {
1160            this.currentHolder = this.chainQueue.poll();
1161            if (this.currentHolder == null) {
1162                this.done = true; // to ensure its done while synchronized
1163            }
1164        }
1165
1166        if (this.currentHolder == null) {
1167            this.previous = null;
1168            // All Done!
1169            this.done(true);
1170            return;
1171        }
1172
1173        Boolean isNextAsync = this.currentHolder.async;
1174        if (isNextAsync == null || factory.shutdown) {
1175            this.currentHolder.run();
1176        } else if (isNextAsync) {
1177            if (this.async) {
1178                this.currentHolder.run();
1179            } else {
1180                impl.postAsync(() -> {
1181                    this.async = true;
1182                    this.currentHolder.run();
1183                });
1184            }
1185        } else {
1186            if (this.async) {
1187                impl.postToMain(() -> {
1188                    this.async = false;
1189                    this.currentHolder.run();
1190                });
1191            } else {
1192                this.currentHolder.run();
1193            }
1194        }
1195    }
1196
1197    private void handleError(Throwable throwable, Task<?, ?> task) {
1198        Exception e = throwable instanceof Exception ? (Exception) throwable : new Exception(throwable);
1199        if (errorHandler != null) {
1200            final TaskChain<?> prev = currentChain.get();
1201            try {
1202                currentChain.set(this);
1203                errorHandler.accept(e, task);
1204            } catch (Exception e2) {
1205                TaskChainUtil.logError("TaskChain Exception in the error handler!" + e2.getMessage());
1206                TaskChainUtil.logError("Current Action Index was: " + currentActionIndex);
1207                e.printStackTrace();
1208            } finally {
1209                currentChain.set(prev);
1210            }
1211        } else {
1212            TaskChainUtil.logError("TaskChain Exception on " + (task != null ? task.getClass().getName() : "Done Hander") + ": " + e.getMessage());
1213            TaskChainUtil.logError("Current Action Index was: " + currentActionIndex);
1214            e.printStackTrace();
1215        }
1216    }
1217
1218    private void abortExecutingChain() {
1219        this.previous = null;
1220        this.chainQueue.clear();
1221        this.done(false);
1222    }
1223
1224    private <R> CompletableFuture<List<R>> getFuture(List<CompletableFuture<R>> futures) {
1225        CompletableFuture<List<R>> onDone = new CompletableFuture<>();
1226        CompletableFuture<?>[] futureArray = new CompletableFuture<?>[futures.size()];
1227        CompletableFuture.allOf((CompletableFuture<?>[]) futures.toArray(futureArray)).whenComplete((aVoid, throwable) -> {
1228            if (throwable != null) {
1229                onDone.completeExceptionally(throwable);
1230            } else {
1231                boolean[] error = {false};
1232                final List<R> results = futures.stream().map(f -> {
1233                    try {
1234                        return f.join();
1235                    } catch (Exception e) {
1236                        error[0] = true;
1237                        TaskChain.this.handleError(e, TaskChain.this.currentHolder.task);
1238                        return null;
1239                    }
1240                }).collect(Collectors.toList());
1241                if (error[0]) {
1242                    onDone.completeExceptionally(new Exception("Future Dependant had an exception"));
1243                } else {
1244                    onDone.complete(results);
1245                }
1246            }
1247        });
1248        return onDone;
1249    }
1250
1251    // </editor-fold>
1252    /* ======================================================================================== */
1253    // <editor-fold desc="// TaskHolder">
1254    /**
1255     * Provides foundation of a task with what the previous task type should return
1256     * to pass to this and what this task will return.
1257     * @param <R> Return Type
1258     * @param <A> Argument Type Expected
1259     */
1260    @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject")
1261    private class TaskHolder<R, A> {
1262        private final TaskChain<?> chain;
1263        private final Task<R, A> task;
1264        final Boolean async;
1265
1266        private boolean executed = false;
1267        private boolean aborted = false;
1268        private final int actionIndex;
1269
1270        private TaskHolder(TaskChain<?> chain, Boolean async, Task<R, A> task) {
1271            this.actionIndex = TaskChain.this.actionIndex++;
1272            this.task = task;
1273            this.chain = chain;
1274            this.async = async;
1275        }
1276
1277        /**
1278         * Called internally by Task Chain to facilitate executing the task and then the next task.
1279         */
1280        private void run() {
1281            final Object arg = this.chain.previous;
1282            this.chain.previous = null;
1283            TaskChain.this.currentActionIndex = this.actionIndex;
1284            final R res;
1285            final TaskChain<?> prevChain = currentChain.get();
1286            try {
1287                currentChain.set(this.chain);
1288                if (this.task instanceof FutureTask) {
1289                    //noinspection unchecked
1290                    final CompletableFuture<R> future = ((FutureTask<R, A>) this.task).runFuture((A) arg);
1291                    if (future == null) {
1292                        throw new NullPointerException("Must return a Future");
1293                    }
1294                    future.whenComplete((r, throwable) -> {
1295                        if (throwable != null) {
1296                            this.chain.handleError(throwable, this.task);
1297                            this.abort();
1298                        } else {
1299                            this.next(r);
1300                        }
1301                    });
1302                } else if (this.task instanceof AsyncExecutingTask) {
1303                    //noinspection unchecked
1304                    ((AsyncExecutingTask<R, A>) this.task).runAsync((A) arg, this::next);
1305                } else {
1306                    //noinspection unchecked
1307                    next(this.task.run((A) arg));
1308                }
1309            } catch (Throwable e) {
1310                //noinspection ConstantConditions
1311                if (e instanceof AbortChainException) {
1312                    this.abort();
1313                    return;
1314                }
1315                this.chain.handleError(e, this.task);
1316                this.abort();
1317            } finally {
1318                if (prevChain != null) {
1319                    currentChain.set(prevChain);
1320                } else {
1321                    currentChain.remove();
1322                }
1323            }
1324        }
1325
1326        /**
1327         * Abort the chain, and clear tasks for GC.
1328         */
1329        private synchronized void abort() {
1330            this.aborted = true;
1331            this.chain.abortExecutingChain();
1332        }
1333
1334        /**
1335         * Accepts result of previous task and executes the next
1336         */
1337        private void next(Object resp) {
1338            synchronized (this) {
1339                if (this.aborted) {
1340                    this.chain.done(false);
1341                    return;
1342                }
1343                if (this.executed) {
1344                    this.chain.done(false);
1345                    throw new RuntimeException("This task has already been executed.");
1346                }
1347                this.executed = true;
1348            }
1349
1350            this.chain.async = !TaskChain.this.impl.isMainThread(); // We don't know where the task called this from.
1351            this.chain.previous = resp;
1352            this.chain.nextTask();
1353        }
1354    }
1355    // </editor-fold>
1356}