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
024package co.aikar.taskchain;
025
026import java.util.ArrayList;
027import java.util.List;
028import java.util.concurrent.CompletableFuture;
029import java.util.stream.Collectors;
030
031public class TaskChainExample {
032    /**
033     * A useless example of registering multiple task signatures and states
034     */
035    public static void example(TaskChainFactory factory) {
036        TaskChainUtil.log("Starting example");
037        final AsyncQueue asyncQueue = factory.getImplementation().getAsyncQueue();
038
039        CompletableFuture<Integer> f1 = new CompletableFuture<>(); // 5
040        CompletableFuture<Integer> f2 = new CompletableFuture<>(); // 3
041        CompletableFuture<Integer> f3 = new CompletableFuture<>(); // 8
042
043        TaskChain<?> chain = factory.newSharedChain("TEST");
044        chain
045            .delay(20 * 3)
046            .sync(() -> {
047                chain.setTaskData("test", 1);
048                TaskChainUtil.log("==> 1st test - completing f3 with 8");
049                f3.complete(8);
050            })
051            .delay(20)
052            .async(() -> {
053                Object test = chain.getTaskData("test");
054                TaskChainUtil.log("==> 2nd test: " + test + " = should be 1");
055            })
056            .sync(TaskChain::abort)
057            .execute((finished) -> TaskChainUtil.log("first test finished: " + finished));
058
059        CompletableFuture<String> falready = new CompletableFuture<>();
060        falready.complete("FOO!");
061        factory.newChain()
062                .current(() -> TaskChainUtil.log("Starting Future task"))
063                .futures(f1, f2, f3)
064                .syncFutures((lists) -> {
065                    final Integer sum = lists.stream().collect(Collectors.summingInt(i -> i));
066                    TaskChainUtil.log("Future complete! got " + lists.size() + " answers that sum to (expect 16): " + sum);
067                    List<CompletableFuture<String>> ret = new ArrayList<>();
068                    CompletableFuture<String> other = new CompletableFuture<>();
069                    asyncQueue.postAsync(() -> other.complete("Result: " + sum));
070                    ret.add(falready);
071                    ret.add(other);
072                    return ret;
073                })
074                .currentLast((results) -> {
075                    TaskChainUtil.log("Results from last future task");
076                    for (String result : results) {
077                        TaskChainUtil.log(result);
078                    }
079                })
080                .execute();
081
082        // This chain essentially appends onto the previous one, and will not overlap
083        asyncQueue.postAsync(() -> {
084            TaskChain<?> chain2 = factory.newSharedChain("TEST");
085            chain2
086                .sync(() -> {
087                    Object test = chain2.getTaskData("test");
088                    TaskChainUtil.log("==> 3rd test: " + test + " = should be null");
089                })
090                .delay(20)
091                .current(() -> {
092                    TaskChainUtil.log("test 2nd chain 20 ticks later - completing f2 with 3");
093                    f2.complete(3);
094                })
095                .execute((finished) -> TaskChainUtil.log("second test finished: " + finished));
096
097            factory
098                .newSharedChain("TEST")
099                .async(() -> TaskChainUtil.log("==> 4th test - should print"))
100                .returnData("notthere")
101                .abortIfNull()
102                .syncLast((val) -> TaskChainUtil.log("Shouldn't execute due to null abort"))
103                .execute(() -> TaskChainUtil.log("finished runnable based test"));
104        });
105        factory
106            .newSharedChain("TEST2")
107            .delay(20 * 3)
108            .sync(() -> TaskChainUtil.log("this should run at same time as 1st test"))
109            .delay(20)
110            .async(() -> TaskChainUtil.log("this should run at same time as 2nd test"))
111            .execute((finished) -> TaskChainUtil.log("TEST2 finished: " + finished));
112        factory.newChain()
113            .asyncFirst(() -> TaskChain.multi(42, "Foo", 4.32F))
114            .asyncLast((d) -> {
115                throw new RuntimeException("Got " + d.var1 +", " + d.var2 + ", " + d.var3);
116            })
117            .execute((finished) -> TaskChainUtil.log("Finished error chain: " + finished), (e, task) -> {
118                TaskChainUtil.logError("Got Exception on task " + task.getClass().getName() + ":" + e.getMessage());
119            });
120        factory
121            .newChain()
122            .sync(() -> TaskChainUtil.log("THE FIRST!"))
123            .delay(20 * 10) // Wait 20s to start any task
124            .async(() -> TaskChainUtil.log("This ran async - with no input or return"))
125            .<Integer>asyncFirstCallback(next -> {
126                // Use a callback to provide result
127                TaskChainUtil.log("this also ran async, but will call next task in 3 seconds.");
128                factory.getImplementation().scheduleTask(60, () -> {
129                    TaskChainUtil.log("completing f1 with 5");
130                    f1.complete(5);
131                    next.accept(3);
132                });
133            })
134            .sync(input -> { // Will be ran 3s later but didn't use .delay()
135                TaskChainUtil.log("should of got 3: " + input);
136                return 5 + input;
137            })
138            .asyncFuture((foo) -> {
139                CompletableFuture<Integer> future = new CompletableFuture<>();
140                asyncQueue.postAsync(() -> {
141                    TaskChainUtil.log("Sleeping 1 before completing future");
142                    try {
143                        Thread.sleep(1000);
144                    } catch (InterruptedException e) {
145                        e.printStackTrace();
146                    }
147                    future.complete(foo + 10);
148                });
149                TaskChainUtil.log("Returning Future");
150                return future;
151            })
152            .storeAsData("Test1")
153            .syncLast(input2 -> TaskChainUtil.log("should be 18: " + input2)) // Consumes last result, but doesn't pass a new one
154            .delay(20) // Wait 1s until next
155            .sync(() -> TaskChainUtil.log("Generic 1s later")) // no input expected, no output, run sync
156            .asyncFirst(() -> 3) // Run task async and return 3
157            .delay(5 * 20) // Wait 5s
158            .asyncLast(input1 -> TaskChainUtil.log("async last value 5s later should be 3: " + input1)) // Run async again, with value of 3
159            .<Integer>returnData("Test1")
160            .asyncLast((val) -> TaskChainUtil.log("Should of got 18 back from data: " + val))
161            .<Integer>returnData("Test1")
162            .abortIf(18)
163            .sync(() -> TaskChainUtil.log("Shouldn't be called"))
164            .execute((finished) -> TaskChainUtil.log("final test chain finished: " + finished));
165
166
167    }
168}