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}