├── .gitignore ├── .travis.yml ├── README.md ├── pom.xml └── src ├── main └── java │ └── io │ └── zatarox │ └── vertx │ └── async │ ├── AsyncFactorySingleton.java │ ├── api │ ├── AsyncCollections.java │ ├── AsyncFactory.java │ ├── AsyncFlows.java │ ├── AsyncMemoize.java │ ├── AsyncUtils.java │ ├── AsyncWorker.java │ ├── AsyncWorkerListener.java │ ├── BiHandler.java │ ├── Pair.java │ ├── RetryOptions.java │ └── package-info.java │ ├── impl │ ├── AbstractRetryOptions.java │ ├── AbstractWorkerImpl.java │ ├── AsyncCargoImpl.java │ ├── AsyncCollectionsImpl.java │ ├── AsyncFlowsImpl.java │ ├── AsyncMemoizeImpl.java │ ├── AsyncQueueImpl.java │ ├── AsyncResultHandlerWrapper.java │ ├── AsyncUtilsImpl.java │ ├── LoopRetryOptions.java │ └── PairImpl.java │ └── utils │ └── DefaultAsyncResult.java ├── samples └── java │ └── io │ └── zatarox │ └── vertx │ └── async │ └── collections │ ├── EachCollection.java │ └── EachMapCollection.java └── test └── java ├── integration └── io │ └── zatarox │ └── vertx │ └── async │ └── AsyncFactorySingletonTest.java └── unit └── io └── zatarox └── vertx └── async ├── fakes ├── FakeAsyncFunction.java ├── FakeAsyncSupplier.java ├── FakeFailingAsyncFunction.java ├── FakeFailingAsyncSupplier.java ├── FakeSuccessfulAsyncFunction.java └── FakeSuccessfulAsyncSupplier.java ├── impl ├── AsyncCargoImplTest.java ├── AsyncCollectionsTest.java ├── AsyncFlowsTest.java ├── AsyncMemoizeImplTest.java ├── AsyncQueueImplTest.java ├── AsyncResultHandlerWrapperTest.java ├── AsyncUtilsTest.java └── LoopRetryOptionsTest.java └── utils └── DefaultAsyncResultTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | *.ipr 4 | *.iws 5 | .classpath 6 | .project 7 | .settings/ 8 | 9 | .gradle/ 10 | build/ 11 | target/ 12 | 13 | mods/ 14 | 15 | *.versionsBackup 16 | /nb-configuration.xml 17 | /nbactions.xml 18 | /.vertx/ 19 | /src/main/groovy/ 20 | /src/main/generated/ 21 | /src/main/resources/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: required 3 | 4 | language: java 5 | 6 | install: 7 | - mvn install -DskipTests=true -DskipPkg=true 8 | 9 | script: 10 | - mvn clean test jacoco:report 11 | 12 | before_install: 13 | - sudo add-apt-repository ppa:openjdk-r/ppa -y 14 | - sudo apt-get update -q 15 | - sudo apt-get install openjdk-8-jdk-headless -y 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vertx-async 2 | [![Build Status via Travis CI](https://travis-ci.org/gchauvet/vertx-async.svg?branch=master)](https://travis-ci.org/gchauvet/vertx-async) 3 | [![Coverage Status](https://coveralls.io/repos/github/gchauvet/vertx-async/badge.svg?branch=master)](https://coveralls.io/github/gchauvet/vertx-async?branch=master) 4 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/8d5ba040f44c44c48d6af3639a5aef35)](https://www.codacy.com/app/gchauvet/vertx-async?utm_source=github.com&utm_medium=referral&utm_content=gchauvet/vertx-async&utm_campaign=Badge_Grade) 5 | [![Dependency Status](https://www.versioneye.com/user/projects/576e250f7bc681003c4900b1/badge.svg?style=flat-square)](https://www.versioneye.com/user/projects/576e250f7bc681003c4900b1) 6 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.zatarox/vertx-async/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.zatarox/vertx-async) 7 | 8 | vertx-async is a portage of caolan/async nodejs module to [Vert.x](http://vertx.io/) framework that provides helpers methods for common async patterns. 9 | 10 | Async provides many methods that include the usual 'functional' suspects (`map`, `reduce`, `filter`, `each`…) as well as some common patterns for asynchronous control flow (`parallel`, `series`, `waterfall`…). All these functions assume you follow the [vert.x convention](http://vertx.io/docs/vertx-core/java/#_don_t_call_us_we_ll_call_you). 11 | 12 |

13 | 14 |

15 | 16 | ## Installation 17 | 18 | vertx-async is available on maven central repository and OSSRH repository. 19 | 20 | ## Quick Examples 21 | 22 | ### Each 23 | 24 | #### On a collection 25 | ```java 26 | @Override 27 | public void start(final Future startFuture) { 28 | AsyncFactorySingleton.getInstance().createCollections(context) 29 | .each(IntStream.iterate(0, i -> i + 1).limit(100).boxed().collect(Collectors.toList()), (item, handler) -> { 30 | System.out.println("get " + item); 31 | handler.handle(DefaultAsyncResult.succeed()); 32 | }, e -> { 33 | System.out.println("done."); 34 | startFuture.complete(e.result()); 35 | }); 36 | } 37 | ``` 38 | 39 | #### On a map 40 | ```java 41 | @Override 42 | public void start(final Future startFuture) { 43 | AsyncFactorySingleton.getInstance().createCollections(context) 44 | .each(IntStream.iterate(0, i -> i + 1).limit(100).boxed().collect(Collectors.toMap(p -> p.toString(), Function.identity())), (item, handler) -> { 45 | System.out.println(item.getKey() + " -> " + item.getValue()); 46 | handler.handle(DefaultAsyncResult.succeed()); 47 | }, e -> { 48 | System.out.println("done."); 49 | startFuture.complete(e.result()); 50 | }); 51 | } 52 | ``` 53 | 54 | There are many more functions available so take a look at the wiki for a full list (work in progress) . This README aims to be comprehensive, so if you feel anything is missing please create a GitHub issue for it. 55 | 56 | ### Multiple callbacks 57 | 58 | Make sure to always calling the callback handler once, instead of a `return` procedural programming statement style, otherwise you will cause multiple callbacks and unpredictable behavior in many cases. 59 | 60 | ## Documentation 61 | 62 | See our wiki (:construction:). 63 | 64 | ### Collections 65 | | | | | | | | | | | | | 66 | |---|---|---|---|---|---|---|---|---|---|---| 67 | | each | map | filter | reject | reduce | transform | detect | sort | some | every | concat | 68 | 69 | ### Control Flow 70 | | | | | | | | | | 71 | |---|---|---|---|---|---|---|---| 72 | | series | parallel | whilst | until | during | forever | waterfall | seq | 73 | | retry | queue | applyEach (each) | times | race | cargo | | | 74 | 75 | # Utils 76 | | | | | | | | | | 77 | |---|---|---|---|---|---|---|---| 78 | | asyncify | constant | memoize | timeout | | | | | 79 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | io.vertx 7 | vertx-ext-parent 8 | 23 9 | 10 | io.zatarox 11 | vertx-async 12 | jar 13 | 1.1.0-SNAPSHOT 14 | Vert.x :: Async 15 | Async helpers for Vert.x 16 | https://github.com/gchauvet/vertx-async 17 | 18 | 19 | Apache License, Version 2.0 20 | http://www.apache.org/licenses/LICENSE-2.0.txt 21 | repo 22 | 23 | 24 | 25 | 26 | Guillaume Chauvet 27 | gchauvet@zatarox.com 28 | gchauvet 29 | http://github.com/gchauvet 30 | 31 | 32 | 33 | scm:git:https://github.com/gchauvet/vertx-async.git 34 | scm:git:git@github.com:gchauvet/vertx-async.git 35 | https://github.com/gchauvet/vertx-async.git 36 | 37 | 38 | UTF-8 39 | 1.8 40 | 1.8 41 | true 42 | 43 | 44 | 45 | 46 | io.vertx 47 | vertx-dependencies 48 | 3.9.12 49 | pom 50 | import 51 | 52 | 53 | 54 | 55 | 56 | io.vertx 57 | vertx-codegen 58 | true 59 | 60 | 61 | io.vertx 62 | vertx-lang-groovy 63 | true 64 | 65 | 66 | io.vertx 67 | vertx-lang-ruby 68 | true 69 | 70 | 71 | io.vertx 72 | vertx-lang-js 73 | true 74 | 75 | 76 | io.vertx 77 | vertx-rx-java 78 | true 79 | 80 | 81 | io.vertx 82 | vertx-docgen 83 | true 84 | 85 | 86 | io.vertx 87 | vertx-codetrans 88 | true 89 | 90 | 91 | io.vertx 92 | vertx-unit 93 | test 94 | 95 | 96 | junit 97 | junit 98 | [4.13.1,) 99 | test 100 | 101 | 102 | org.mockito 103 | mockito-core 104 | 1.10.19 105 | test 106 | 107 | 108 | 109 | 110 | sonatype-nexus-snapshots 111 | Sonatype Nexus snapshot repository 112 | https://oss.sonatype.org/content/repositories/snapshots 113 | 114 | 115 | sonatype-nexus-staging 116 | Sonatype Nexus release repository 117 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 118 | 119 | 120 | 121 | 122 | 123 | org.eluder.coveralls 124 | coveralls-maven-plugin 125 | 4.3.0 126 | 127 | 128 | org.jacoco 129 | jacoco-maven-plugin 130 | 0.8.7 131 | 132 | 133 | prepare-agent 134 | 135 | prepare-agent 136 | 137 | 138 | 139 | 140 | 141 | org.codehaus.mojo 142 | build-helper-maven-plugin 143 | 144 | 145 | add-integration-test-source 146 | process-resources 147 | 148 | add-test-source 149 | 150 | 151 | 152 | src/test/java/integration 153 | 154 | 155 | 156 | 157 | 158 | 159 | src/test/java/unit 160 | 161 | 162 | 163 | publish 164 | 165 | 166 | 167 | org.apache.maven.plugins 168 | maven-gpg-plugin 169 | 3.0.1 170 | 171 | 172 | sign-artifacts 173 | verify 174 | 175 | sign 176 | 177 | 178 | 179 | 180 | 181 | org.sonatype.plugins 182 | nexus-staging-maven-plugin 183 | 1.6.12 184 | true 185 | 186 | ossrh 187 | https://oss.sonatype.org/ 188 | true 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/AsyncFactorySingleton.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async; 17 | 18 | import io.zatarox.vertx.async.api.AsyncFactory; 19 | import io.zatarox.vertx.async.api.AsyncUtils; 20 | import io.vertx.core.Context; 21 | import io.zatarox.vertx.async.api.AsyncCollections; 22 | import io.zatarox.vertx.async.api.AsyncFlows; 23 | import io.zatarox.vertx.async.impl.AsyncCollectionsImpl; 24 | import io.zatarox.vertx.async.impl.AsyncFlowsImpl; 25 | import io.zatarox.vertx.async.impl.AsyncUtilsImpl; 26 | 27 | public final class AsyncFactorySingleton implements AsyncFactory { 28 | 29 | private static AsyncFactorySingleton instance = null; 30 | 31 | private AsyncFactorySingleton() { 32 | } 33 | 34 | @Override 35 | public AsyncUtils createUtils(final Context context) { 36 | return new AsyncUtilsImpl(context); 37 | } 38 | 39 | @Override 40 | public AsyncCollections createCollections(final Context context) { 41 | return new AsyncCollectionsImpl(context); 42 | } 43 | 44 | @Override 45 | public AsyncFlows createFlows(final Context context) { 46 | return new AsyncFlowsImpl(context); 47 | } 48 | 49 | public static AsyncFactorySingleton getInstance() { 50 | if (instance == null) { 51 | instance = new AsyncFactorySingleton(); 52 | } 53 | return instance; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/AsyncCollections.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.api; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import java.util.Collection; 21 | import java.util.Comparator; 22 | import java.util.List; 23 | import java.util.Map; 24 | 25 | public interface AsyncCollections { 26 | 27 | /** 28 | * Applies {@code consumer} to each item in {@code collection}, 29 | * concatenating the results. Returns the concatenated list. The 30 | * {@code iteratee}s are called in parallel, and the results are 31 | * concatenated as they return. There is no guarantee that the results array 32 | * will be returned in the original order of {@code collection} passed to 33 | * the {@code iteratee} function. 34 | * 35 | * @param Define input type. 36 | * @param Define output type. 37 | * @param iterable A collection to iterate over. 38 | * @param consumer A function to apply to each item in collection 39 | * @param handler A callback which is called after all the {@code iterable} 40 | * functions have finished, or an error occurs. 41 | */ 42 | void concat(final Collection iterable, final BiHandler>>> consumer, final Handler>> handler); 43 | 44 | /** 45 | * Returns the first value in {@code collection} that passes an async truth 46 | * test. The {@code function} is applied in parallel, meaning the first 47 | * iteratee to return {@code true} will fire the detect {@code callback} 48 | * with that result. That means the result might not be the first item in 49 | * the original {@code collection} (in terms of order) that passes the test. 50 | * 51 | * @param Define the manipulated type. 52 | * @param collection A collection to iterate over. 53 | * @param function A truth test to apply to each item in {@code collection}. 54 | * The iteratee is passed a {@code callback} which must be called with a 55 | * boolean argument once it has completed. 56 | * @param handler A callback which is called as soon as any iteratee returns 57 | * {@code true}, or after all the {@code function} functions have finished. 58 | * Result will be the first item in the array that passes the truth test 59 | * (function) or the value {@code null} if none passed. 60 | */ 61 | 62 | void detect(final Collection collection, final BiHandler>> function, final Handler> handler); 63 | 64 | /** 65 | * Applies the function {@code consumer} to each item in {@code iterable}, 66 | * in parallel. The {@code consumer} is called with an item from the list, 67 | * and a callback when it has finished. If the {@code consumer} passes an 68 | * error to its {@code callback}, the main {@code handler} (for the 69 | * {@code each} function) is immediately called with the error. 70 | * 71 | * Note, that since this function applies {@code consumer} to each item in 72 | * parallel, there is no guarantee that the consumer functions will complete 73 | * in order. 74 | * 75 | * @param Define the manipulated type. 76 | * @param iterable A collection to iterate over. 77 | * @param consumer A function to apply to each item in {@code iterable}. The 78 | * iteratee is passed a {@code consumer} which must be called once it has 79 | * completed. If no error has occurred, the {@code callback} should be run 80 | * without arguments or with an explicit {@code null} argument. The array 81 | * index is not passed to the consumer. If you need the index, use 82 | * {@code eachOf}. 83 | * @param handler A callback which is called when all {@code consumer} 84 | * functions have finished, or an error occurs. 85 | */ 86 | void each(final Collection iterable, final BiHandler>> consumer, final Handler> handler); 87 | 88 | /** 89 | * Like {@code each}, except that it passes the tuple key/value as argument 90 | * to the consumer. 91 | * 92 | * @param Define type of key. 93 | * @param Define type of value. 94 | * @param iterable A collection to iterate over. 95 | * @param consumer A function to apply to each item in {@code iterable}. The 96 | * {@code key} is the item's key. The iteratee is passed a {@code handler} 97 | * which must be called once it has completed. If no error has occurred, the 98 | * callback should be run without arguments or with an explicit {@code null} 99 | * argument. 100 | * @param handler A callback which is called when all {@code consumer} 101 | * functions have finished, or an error occurs. 102 | */ 103 | void each(final Map iterable, final BiHandler, Handler>> consumer, final Handler> handler); 104 | 105 | /** 106 | * Returns {@code true} if every element in {@code collection} satisfies an 107 | * async test. If any iteratee call returns {@code false}, the main 108 | * {@code callback} is immediately called. 109 | * 110 | * @param Define the manipulated type. 111 | * @param collection A collection to iterate over. 112 | * @param function A truth test to apply to each item in the collection in 113 | * parallel. 114 | * @param handler A callback which is called after all the {code collection} 115 | * functions have finished. Result will be either {@code true} or 116 | * {@code false} depending on the values of the async tests. 117 | */ 118 | void every(final Collection collection, final BiHandler>> function, final Handler> handler); 119 | 120 | /** 121 | * Returns a new collection of all the values in {@code iterable} which pass 122 | * an async truth test. This operation is performed in parallel, but the 123 | * results array will be in the same order as the original. 124 | * 125 | * @param Define the manipulated type. 126 | * @param iterable A collection to iterate over. 127 | * @param consumer A truth test to apply to each item in {@code iterable}. 128 | * The {@code consumer} is passed a {@code handler}, which must be called 129 | * with a boolean argument once it has completed. 130 | * @param handler A callback which is called after all the {@code consumer} 131 | * functions have finished. 132 | */ 133 | void filter(final Collection iterable, final BiHandler>> consumer, final Handler>> handler); 134 | 135 | /** 136 | * Produces a new collection of values by mapping each value in 137 | * {@code iterable} through the {@code consumer} function. The 138 | * {@code consumer} is called with an item from {@code iterbale} and a 139 | * callback for when it has finished processing. Each of these callback 140 | * takes 2 arguments: an {@code error}, and the transformed item from 141 | * {@code iterable}. If {@code consumer} passes an error to its callback, 142 | * the main {@code handler} (for the {@code map} function) is immediately 143 | * called with the error. 144 | * 145 | * Note, that since this function applies the {@code consumer} to each item 146 | * in parallel, there is no guarantee that the {@code consumer} functions 147 | * will complete in order. However, the results array will be in the same 148 | * order as the original {@code iterable}. 149 | * 150 | * @param Define input type. 151 | * @param Define output type. 152 | * @param iterable A collection to iterate over. 153 | * @param consumer A function to apply to each item in {@code iterable}. The 154 | * iteratee is passed a {@code handler} which must be called once it has 155 | * completed with an error and a transformed item. Invoked with (item, 156 | * callback). 157 | * @param handler A callback which is called when all {@code consumer} 158 | * functions have finished, or an error occurs. Results is a List of the 159 | * transformed items from the {@code iterable}. 160 | */ 161 | void map(final List iterable, final BiHandler>> consumer, final Handler>> handler); 162 | 163 | /** 164 | * Reduces {@code collection} into a single value using an async 165 | * {@code consumer} to return each successive step. {@code memo} is the 166 | * initial state of the reduction. This function only operates in series. 167 | * 168 | * This function is for situations where each step in the reduction needs to 169 | * be async; if you can get the data before reducing it, then it's probably 170 | * a good idea to do so. 171 | * 172 | * @param Define the type of input data 173 | * @param Define the type of output data 174 | * @param collection A collection to iterate over. 175 | * @param memo Initial state of the reduction. 176 | * @param function A function applied to each item in the array to produce 177 | * the next step in the reduction. The {@code function} is passed a 178 | * {@code handler} which accepts an optional error as its first argument, 179 | * and the state of the reduction as the second. If an error is passed to 180 | * the callback, the reduction is stopped and the main {@code handler} is 181 | * immediately called. 182 | * @param handler A callback which is called after all the {@code function} 183 | * functions have finished. Result is the transformed accumulator. 184 | */ 185 | void reduce(final Collection collection, final O memo, final BiHandler, Handler>> function, final Handler> handler); 186 | 187 | /** 188 | * The opposite of {@code filter}. Removes values that pass an {@code async} 189 | * truth test. 190 | * 191 | * @param Define the manipulated type. 192 | * @param iterable A collection to iterate over. 193 | * @param consumer A falsy test to apply to each item in {@code iterable}. 194 | * The {@code consumer} is passed a {@code handler}, which must be called 195 | * with a boolean argument once it has completed. 196 | * @param handler A callback which is called after all the {@code consumer} 197 | * functions have finished. 198 | */ 199 | void reject(final Collection iterable, final BiHandler>> consumer, final Handler>> handler); 200 | 201 | /** 202 | * Returns {@code true} if at least one element in the {@code collection} 203 | * satisfies an async test. If any iteratee call returns {@code true}, the 204 | * main {@code callback} is immediately called. 205 | * 206 | * @param Define the manipulated type. 207 | * @param collection A collection to iterate over. 208 | * @param function A truth test to apply to each item in the array in 209 | * parallel. 210 | * @param handler A callback which is called as soon as any iteratee returns 211 | * {@code true}, or after all the iteratee functions have finished. Result 212 | * will be either {@code true} or {@code false} depending on the values of 213 | * the async tests. 214 | */ 215 | void some(final Collection collection, final BiHandler>> function, final Handler> handler); 216 | 217 | /** 218 | * Sorts a list by the results of running each {@code collection} value 219 | * through the internal comparator. 220 | * 221 | * @param Define the manipulated type. 222 | * @param iterable A collection to iterate over. 223 | * @param handler A callback which is called after all the {@code iterable} 224 | * functions have finished, or an error occurs. Results is the items from 225 | * the original {@code collection} sorted by the values returned by the 226 | * {@code iterable} calls. 227 | */ 228 | void sort(final Collection iterable, final Handler>> handler); 229 | 230 | /** 231 | * Sorts a list by the results of running each {@code collection} value 232 | * through an async {@code comparator}. 233 | * 234 | * @param Define the manipulated type. 235 | * @param iterable A collection to iterate over. 236 | * @param comparator A function used as comparator. 237 | * @param handler A callback which is called after all {@code comparator} 238 | * functions have finished, or an error occurs. Results is the items from 239 | * the original {@code collection} sorted by the values returned by the 240 | * {@code comparator} calls. 241 | */ 242 | void sort(final Collection iterable, final Comparator comparator, final Handler>> handler); 243 | 244 | /** 245 | * A relative of {@code reduce}. Takes a Collection, and iterates over each 246 | * element in series, each step potentially mutating an {@code accumulator} 247 | * value. The type of the accumulator defaults to the type of collection 248 | * passed in. 249 | * 250 | * @param Define the type of input data 251 | * @param Define the type of output data 252 | * @param iterable A collection to iterate over. 253 | * @param consumer A function applied to each item in the collection that 254 | * potentially modifies the accumulator. The {@code consumer} is passed a 255 | * {@code handler}. If an error is passed to the callback, the transform is 256 | * stopped and the main {@code handler} is immediately called with the 257 | * error. 258 | * @param handler A callback which is called after all the {@code consumer} 259 | * functions have finished. Result is the transformed accumulator. 260 | */ 261 | void transform(final Collection iterable, final BiHandler>> consumer, final Handler>> handler); 262 | 263 | /** 264 | * A relative of {@code reduce}. Takes a Map, and iterates over each element 265 | * in series, each step potentially mutating an {@code accumulator} value. 266 | * The type of the accumulator defaults to the type of collection passed in. 267 | * 268 | * @param Define the type of input key. 269 | * @param Define the type of input value. 270 | * @param Define the type of output key. 271 | * @param Define the type of output value. 272 | * @param iterable A collection to iterate over. 273 | * @param consumer A function applied to each item in the collection that 274 | * potentially modifies the accumulator. The {@code consumer} is passed a 275 | * {@code handler}. If an error is passed to the callback, the transform is 276 | * stopped and the main {@code handler} is immediately called with the 277 | * error. 278 | * @param handler A callback which is called after all the {@code consumer} 279 | * functions have finished. Result is the transformed accumulator. 280 | */ 281 | void transform(final Map iterable, final BiHandler, Handler>>> consumer, final Handler>> handler); 282 | 283 | } 284 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/AsyncFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.api; 17 | 18 | import io.vertx.core.Context; 19 | 20 | public interface AsyncFactory { 21 | 22 | AsyncCollections createCollections(final Context context); 23 | 24 | AsyncFlows createFlows(final Context context); 25 | 26 | AsyncUtils createUtils(final Context context); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/AsyncFlows.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.api; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.zatarox.vertx.async.impl.AbstractRetryOptions; 21 | import java.util.Collection; 22 | import java.util.List; 23 | import java.util.function.BooleanSupplier; 24 | 25 | public interface AsyncFlows { 26 | 27 | /** 28 | * Creates a cargo object with the specified payload. Tasks added to the 29 | * cargo will be processed altogether (up to the payload limit). If the 30 | * worker is in progress, the task is queued until it becomes available. 31 | * Once the worker has completed some tasks, each callback of those tasks is 32 | * called. Check out these animations for how cargo and queue work. 33 | * 34 | * While queue passes only one task to one of a group of workers at a time, 35 | * cargo passes an array of tasks to a single worker, repeating when the 36 | * worker is finished. 37 | * 38 | * @param The manipulated type. 39 | * @param worker The worker used to process tasks 40 | * @return A cargo for processing tasks through the provided worker 41 | * function. 42 | */ 43 | AsyncWorker createCargo(final BiHandler>> worker); 44 | 45 | /** 46 | * Creates a queue object with the specified concurrency. Tasks added to the 47 | * queue are processed in parallel (up to the concurrency limit). If all 48 | * workers are in progress, the task is queued until one becomes available. 49 | * Once a worker completes a task, that task's callback is called. 50 | * 51 | * @param The manipulated type. 52 | * @param worker The worker used to process the queue 53 | * @return A queue of tasks for the worker function to complete. 54 | */ 55 | AsyncWorker createQueue(final BiHandler>> worker); 56 | 57 | /** 58 | * Applies the provided arguments to each function in the array, calling 59 | * {@code handler} after all functions have completed. If you only provide 60 | * the first argument, then it will return a function which lets you pass in 61 | * the arguments as if it were a single function call. 62 | * 63 | * @param The manipulated type. 64 | * @param args An object representing arguments. 65 | * @param functions A collection of asynchronous functions to all call with 66 | * the same arguments. 67 | * @param handler The final argument should be the callback, called when all 68 | * functions have completed processing. 69 | */ 70 | void each(final Collection>>> functions, final T args, final Handler> handler); 71 | 72 | /** 73 | * Calls the asynchronous function {@code task} with a callback parameter 74 | * that allows it to call itself again, in series, indefinitely. If an error 75 | * is passed to the callback then {@code handler} is called with the error, 76 | * and execution stops, otherwise it will never be called. 77 | * 78 | * @param Define the manipulated data type. 79 | * @param task A function to call repeatedly. 80 | * @param handler when {@code task} passes an error to it's callback, this 81 | * function will be called, and execution stops. 82 | */ 83 | void forever(final Handler>> task, final Handler> handler); 84 | 85 | /** 86 | * Run the {@code tasks} collection of functions in parallel, without 87 | * waiting until the previous function has completed. If any of the 88 | * functions pass an error to its callback, the main {@code handler} is 89 | * immediately called with the value of the error. Once the {@code tasks} 90 | * have completed, the results are passed to the final {@code handler} as an 91 | * array. 92 | * 93 | * **Note:** {@code parallel} is about kicking-off I/O tasks in parallel, 94 | * not about parallel execution of code. If your tasks do not use any timers 95 | * or perform any I/O, they will actually be executed in series. Any 96 | * synchronous setup sections for each task will happen one after the other. 97 | * 98 | * @param Define the manipulated data type. 99 | * @param tasks Collection of tasks to run. 100 | * @param handler A callback to run once all the functions have completed 101 | * successfully. This function gets a results array (or object) containing 102 | * all the result arguments passed to the task callbacks. 103 | */ 104 | void parallel(final List>>> tasks, final Handler>> handler); 105 | 106 | /** 107 | * Runs the {@code tasks} array of functions in parallel, without waiting 108 | * until the previous function has completed. Once any the {@code tasks} 109 | * completed or pass an error to its callback, the main {@code handler} is 110 | * immediately called. 111 | * 112 | * @param Define the manipulated type. 113 | * @param tasks An array containing functions to run. 114 | * @param handler A callback to run once any of the functions have 115 | * completed. This function gets an error or result from the first function 116 | * that completed. 117 | */ 118 | void race(final Collection>>> tasks, final Handler> handler); 119 | 120 | /** 121 | * Attempts to get a successful response from {@code task} no more than 122 | * {@code times} times before returning an error. If the task is successful, 123 | * the {@code callback} will be passed the result of the successful task. If 124 | * all attempts fail, the callback will be passed the error and result (if 125 | * any) of the final attempt. 126 | * 127 | * @param Define the manipulated data type. 128 | * @param task A function which receives two arguments: (1) a {@code task} 129 | * which must be called when finished, passing {@code err} (which can be 130 | * {@code null}) and the {@code result} of the function's execution, and (2) 131 | * a {@code results} object, containing the results of the previously 132 | * executed functions (if nested inside another control flow). 133 | * @param options Define options for retries 134 | * @param handler An optional callback which is called when the task has 135 | * succeeded, or after the final failed attempt. It receives the {@code err} 136 | * and {@code result} arguments of the last attempt at completing the 137 | * {@code task}. 138 | */ 139 | void retry(final AbstractRetryOptions options, final Handler>> task, final Handler> handler); 140 | 141 | /** 142 | * Creates a function which is a composition of the passed asynchronous 143 | * functions. Each function consumes the return value of the previous 144 | * function. 145 | * 146 | * @param Define input data type of functions 147 | * @param Define ouput data type of functions 148 | * 149 | * @param functions Asynchronous functions to seq 150 | * @return A proxy for asynchronous functions 151 | */ 152 | BiHandler>> seq(final BiHandler>>... functions); 153 | 154 | /** 155 | * Run the functions in the {@code tasks} collection in series, each one 156 | * running once the previous function has completed. If any functions in the 157 | * series pass an error to its callback, no more functions are run, and 158 | * {@code handler} is immediately called with the value of the error. 159 | * Otherwise, {@code handler} receives an array of results when 160 | * {@code tasks} have completed. 161 | * 162 | * It is also possible to use an object instead of an array. Each property 163 | * will be run as a function, and the results will be passed to the final 164 | * {@code callback} as an object instead of an array. 165 | * 166 | * @param Define the manipulated data type. 167 | * @param tasks A collection containing functions to run, each function is 168 | * passed a {@code handler} it must call on completion with an optional 169 | * error and an optional {@code result} value. 170 | * @param handler An optional handler to run once all the functions have 171 | * completed. This function gets a results array (or object) containing all 172 | * the result arguments passed to the {@code task} handlers. 173 | */ 174 | void series(final Collection>>> tasks, final Handler>> handler); 175 | 176 | /** 177 | * Calls the {@code consumer} function {@code counter} times, and 178 | * accumulates results in the same manner you would use with 179 | * {@code AsyncCollections.map}. 180 | * 181 | * @param Define the manipulated type. 182 | * @param counter The number of times to run the function. 183 | * @param consumer The function to call {@code n} times. Invoked with the 184 | * iteration index and a callback. 185 | * @param handler A callback which is called after the test function has 186 | * failed and repeated execution of {@code consumer} has stopped. 187 | */ 188 | void times(final int counter, final BiHandler>> consumer, final Handler>> handler); 189 | 190 | /** 191 | * Repeatedly call {@code consumer} until {@code tester} returns 192 | * {@code false}. Calls {@code handler} when stopped, or an error occurs. 193 | * 194 | * @param tester synchronous truth test to perform after each execution of 195 | * {@code consumer}. 196 | * @param consumer A function which is called each time {@code tester} 197 | * passes. 198 | * @param handler A callback which is called after the test function has 199 | * failed and repeated execution of {@code consumer} has stopped. 200 | */ 201 | void until(final BooleanSupplier tester, final Handler>> consumer, final Handler> handler); 202 | 203 | /** 204 | * Runs the {@code tasks} array of functions in series, each passing their 205 | * results to the next in the array. However, if any of the {@code tasks} 206 | * pass an error to their own callback, the next function is not executed, 207 | * and the main {@code callback} is immediately called with the error. 208 | * 209 | * @param Define input data type of functions 210 | * @param Define ouput data type of functions 211 | * @param tasks An array of functions to run, each function is passed with 212 | * previously computed result thougth the {@code handler}. 213 | * @param handler Handler to run once all the functions have completed. This 214 | * will be passed the results of the last task's callback. 215 | */ 216 | void waterfall(final Iterable>>> tasks, final Handler> handler); 217 | 218 | /** 219 | * Repeatedly call {@code consumer}, while {@code tester} returns 220 | * {@code true}. Calls {@code handler} when stopped, or an error occurs. 221 | * 222 | * @param tester A synchronous truth test to perform before each execution 223 | * of {@code consumer}. 224 | * @param consumer A function which is called each time {@code tester} 225 | * passes. 226 | * @param handler A callback which is called after the test function has 227 | * failed and repeated execution of {@code consumer} has stopped. 228 | */ 229 | void whilst(final BooleanSupplier tester, final Handler>> consumer, final Handler> handler); 230 | 231 | /** 232 | * Repeatedly call {@code consumer}, while {@code tester} returns 233 | * {@code true}. Calls {@code handler} when stopped, or an error occurs. 234 | * 235 | * @param tester A asynchronous truth test to perform before each execution 236 | * of {@code consumer}. 237 | * @param consumer A function which is called each time {@code tester} 238 | * passes. 239 | * @param handler A callback which is called after the test function has 240 | * failed and repeated execution of {@code consumer} has stopped. 241 | */ 242 | void whilst(final Handler>> tester, final Handler>> consumer, final Handler> handler); 243 | 244 | } 245 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/AsyncMemoize.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.api; 17 | 18 | import io.vertx.codegen.annotations.VertxGen; 19 | 20 | @VertxGen 21 | public interface AsyncMemoize { 22 | 23 | /** 24 | * @param argument Argument used as key. 25 | * @return data associated to argument. 26 | */ 27 | O get(final I argument); 28 | 29 | /** 30 | * @param argument Argument used as key 31 | * @return True if result associated to argument have been removed. 32 | */ 33 | boolean unset(final I argument); 34 | 35 | /** 36 | * Clean cache 37 | */ 38 | void clear(); 39 | 40 | /** 41 | * @return True if is empty 42 | */ 43 | boolean isEmpty(); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/AsyncUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.api; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import java.util.concurrent.TimeUnit; 21 | import java.util.function.Function; 22 | 23 | public interface AsyncUtils { 24 | 25 | /** 26 | * Take a sync function and make it async, passing its return value to a 27 | * callback. This is useful for plugging sync functions into a waterfall, 28 | * series, or other async functions. Any arguments passed to the generated 29 | * function will be passed to the wrapped function (except for the final 30 | * callback argument). Errors thrown will be passed to the callback. 31 | * 32 | * @param Handled input generic type. 33 | * @param Handled output generic type. 34 | * @param function The synchronous function to manage. 35 | * @return An asynchronous wrapper ready to be use with Vertx. 36 | */ 37 | BiHandler>> asyncify(final Function function); 38 | 39 | /** 40 | * Returns a function that when called, calls-back with the values provided. 41 | * Useful as the first function in a {@code waterfall}. 42 | * 43 | * @param Handled generic type. 44 | * @param value value of the "constant". 45 | * @return An handler wrapper of "constant" value. 46 | */ 47 | Handler>> constant(final T value); 48 | 49 | /** 50 | * Caches the results of an async function. When creating a hash to store 51 | * function results against, the callback is omitted from the hash and an 52 | * optional hash function can be used. 53 | * 54 | * @param Handled input generic type. 55 | * @param Handled output generic type. 56 | * @param function The function to proxy and cache results from. 57 | * @return A proxy cache for the function. 58 | */ 59 | AsyncMemoize memoize(final BiHandler>> function); 60 | 61 | /** 62 | * Emulate a time limit on an asynchronous function. If the function does 63 | * not call its callback within the specified miliseconds, it will be called 64 | * with a timeout error. 65 | * 66 | * @param Handled generic type 67 | * @param function A function which will be runned. 68 | * @param unit Time unit used for the delay time. 69 | * @param delay A time delay in the specified time unit. 70 | * @param handler An handler called when function finished or timeout is 71 | * reached 72 | */ 73 | void timeout(final Handler>> function, final TimeUnit unit, final long delay, final Handler> handler); 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/AsyncWorker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.api; 17 | 18 | import io.vertx.codegen.annotations.VertxGen; 19 | import io.vertx.core.AsyncResult; 20 | import io.vertx.core.Handler; 21 | 22 | @VertxGen 23 | public interface AsyncWorker { 24 | 25 | 26 | /** 27 | * Add a consumer in the pool 28 | * 29 | * @param task The task to run 30 | * @param handler Result handler associated with the declared consumer 31 | * @param top Add to the top of the queue ? 32 | * @return True is operation is successful 33 | */ 34 | boolean add(final T task, final Handler> handler, final boolean top); 35 | 36 | /** 37 | * @param listener Listener to add 38 | * @return True if listener is added 39 | */ 40 | boolean add(final AsyncWorkerListener listener); 41 | 42 | /** 43 | * @return The concurrency limit 44 | */ 45 | int getConcurrency(); 46 | 47 | /** 48 | * @return Number of running workers 49 | */ 50 | int getRunning(); 51 | 52 | /** 53 | * @return Returning false if there are items waiting or being processed, or 54 | * true if not. 55 | */ 56 | boolean isIdle(); 57 | 58 | /** 59 | * Removes the drain callback and empties remaining tasks from the queue 60 | * forcing it to go idle. 61 | */ 62 | void clear(); 63 | 64 | /** 65 | * @return A boolean for determining whether the queue is in a paused state. 66 | */ 67 | boolean isPaused(); 68 | 69 | /** 70 | * @param paused A function that pauses or not the processing of tasks. 71 | */ 72 | void setPaused(final boolean paused); 73 | 74 | /** 75 | * @param listener Listener to remove 76 | * @return True if listener was removed 77 | */ 78 | boolean remove(final AsyncWorkerListener listener); 79 | 80 | /** 81 | * @param concurrency Define concurrencu limit for workers 82 | */ 83 | void setConcurrency(int concurrency); 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/AsyncWorkerListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.api; 17 | 18 | import io.vertx.codegen.annotations.VertxGen; 19 | 20 | @VertxGen 21 | public interface AsyncWorkerListener { 22 | 23 | /** 24 | * When the processing pool become empty 25 | * @param instance Object who raised the notification 26 | */ 27 | void poolEmpty(final AsyncWorker instance); 28 | 29 | /** 30 | * When the processing pool become full 31 | * @param instance Object who raised the notification 32 | */ 33 | void poolFull(final AsyncWorker instance); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/BiHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.api; 17 | 18 | @FunctionalInterface 19 | public interface BiHandler { 20 | 21 | public void handle(K key, V value); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/Pair.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.api; 17 | 18 | import io.vertx.codegen.annotations.VertxGen; 19 | 20 | @VertxGen 21 | public interface Pair { 22 | 23 | K getKey(); 24 | 25 | V getValue(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/RetryOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.api; 17 | 18 | import io.vertx.codegen.annotations.*; 19 | import io.vertx.core.AsyncResult; 20 | import io.vertx.core.Handler; 21 | 22 | @VertxGen 23 | public interface RetryOptions { 24 | 25 | @GenIgnore//@Todo 26 | Handler build(final Handler>> task, final Handler> handler); 27 | 28 | long getTries(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/api/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | @ModuleGen(name = "async", groupPackage="io.zatarox.vertx.async") 18 | package io.zatarox.vertx.async.api; 19 | 20 | import io.vertx.codegen.annotations.ModuleGen; 21 | 22 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/AbstractRetryOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.zatarox.vertx.async.api.RetryOptions; 19 | 20 | /** 21 | * This class define an abstract parameters entity for a retry method call. 22 | * @param Handled result type 23 | */ 24 | public abstract class AbstractRetryOptions implements RetryOptions { 25 | 26 | protected final long tries; 27 | 28 | protected AbstractRetryOptions(long tries) { 29 | if (tries < 1) { 30 | throw new IllegalArgumentException("Tries must be positive"); 31 | } 32 | 33 | this.tries = tries; 34 | } 35 | 36 | @Override 37 | public long getTries() { 38 | return tries; 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/AbstractWorkerImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.core.Handler; 19 | import io.vertx.core.Vertx; 20 | import io.vertx.core.impl.ConcurrentHashSet; 21 | import java.util.Set; 22 | import java.util.concurrent.atomic.AtomicBoolean; 23 | import java.util.concurrent.atomic.AtomicInteger; 24 | import io.zatarox.vertx.async.api.AsyncWorker; 25 | import io.zatarox.vertx.async.api.AsyncWorkerListener; 26 | 27 | public abstract class AbstractWorkerImpl implements AsyncWorker, Handler { 28 | 29 | protected final Set listeners = new ConcurrentHashSet(); 30 | protected final AtomicInteger concurrency = new AtomicInteger(0); 31 | protected final AtomicBoolean paused = new AtomicBoolean(false); 32 | protected final AtomicInteger current = new AtomicInteger(0); 33 | 34 | protected AbstractWorkerImpl(final int concurrency) { 35 | setConcurrency(concurrency); 36 | } 37 | 38 | public int getConcurrency() { 39 | return concurrency.get(); 40 | } 41 | 42 | public void setConcurrency(int concurrency) { 43 | if (concurrency < 1) { 44 | throw new IllegalArgumentException("Must be positive"); 45 | } 46 | this.concurrency.set(concurrency); 47 | } 48 | 49 | public int getRunning() { 50 | return current.get(); 51 | } 52 | 53 | public boolean add(final AsyncWorkerListener listener) { 54 | return listeners.add(listener); 55 | } 56 | 57 | public boolean remove(final AsyncWorkerListener listener) { 58 | return listeners.remove(listener); 59 | } 60 | 61 | @Override 62 | public boolean isPaused() { 63 | return paused.get(); 64 | } 65 | 66 | @Override 67 | public void setPaused(boolean paused) { 68 | this.paused.set(paused); 69 | if (!paused && current.get() < 1) { 70 | Vertx.currentContext().runOnContext(this); 71 | } 72 | } 73 | 74 | protected void fireEmptyPool() { 75 | listeners.stream().forEach(listener -> { 76 | listener.poolEmpty(this); 77 | }); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/AsyncCargoImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.vertx.core.Vertx; 21 | import io.zatarox.vertx.async.api.BiHandler; 22 | import io.zatarox.vertx.async.api.Pair; 23 | import java.util.ArrayList; 24 | import java.util.Collection; 25 | import java.util.Deque; 26 | import java.util.concurrent.ConcurrentLinkedDeque; 27 | import java.util.concurrent.atomic.AtomicBoolean; 28 | 29 | public final class AsyncCargoImpl extends AbstractWorkerImpl> { 30 | 31 | private final BiHandler>>>, Handler>> worker; 32 | private final Deque>>> tasks = new ConcurrentLinkedDeque(); 33 | 34 | public AsyncCargoImpl(final BiHandler>>>, Handler>> worker, final int payload) { 35 | super(payload); 36 | this.worker = worker; 37 | } 38 | 39 | public AsyncCargoImpl(final BiHandler>>>, Handler>> worker) { 40 | this(worker, Integer.MAX_VALUE); 41 | } 42 | 43 | @Override 44 | public boolean add(final Collection tasks, final Handler> handler, final boolean top) { 45 | try { 46 | final AtomicBoolean result = new AtomicBoolean(true); 47 | tasks.stream().forEach(t -> { 48 | result.set(result.get() && this.addInternal(t, handler, top)); 49 | }); 50 | return result.get(); 51 | } finally { 52 | if (current.get() < 1 && !paused.get()) { 53 | Vertx.currentContext().runOnContext(this); 54 | } 55 | } 56 | } 57 | 58 | private boolean addInternal(final T task, final Handler> handler, final boolean top) { 59 | final Pair>> item = new PairImpl(task, handler); 60 | final boolean result; 61 | if (!top) { 62 | result = tasks.offer(item); 63 | } else { 64 | result = tasks.offerFirst(item); 65 | } 66 | return result; 67 | } 68 | 69 | @Override 70 | public boolean isIdle() { 71 | return current.get() == 0 && tasks.isEmpty(); 72 | } 73 | 74 | @Override 75 | public void clear() { 76 | tasks.clear(); 77 | } 78 | 79 | @Override 80 | public void handle(Void event) { 81 | if (tasks.isEmpty()) { 82 | fireEmptyPool(); 83 | } else if (!paused.get()) { 84 | final int size = tasks.size() < concurrency.get() ? tasks.size() : concurrency.get(); 85 | final Collection>>> tasksToPass = new ArrayList<>(size); 86 | for (int i = 0; i < size; i++) { 87 | tasksToPass.add(tasks.poll()); 88 | } 89 | current.incrementAndGet(); 90 | if (size == tasksToPass.size()) { 91 | fireFullPool(); 92 | } 93 | Vertx.currentContext().runOnContext(event1 -> { 94 | worker.handle(tasksToPass, event2 -> { 95 | current.decrementAndGet(); 96 | this.handle(event1); 97 | }); 98 | }); 99 | } 100 | } 101 | 102 | protected void fireFullPool() { 103 | listeners.stream().forEach(listener -> { 104 | listener.poolFull(this); 105 | }); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/AsyncCollectionsImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 19 | import io.vertx.core.AsyncResult; 20 | import io.vertx.core.Context; 21 | import io.vertx.core.Handler; 22 | import io.zatarox.vertx.async.api.AsyncCollections; 23 | import io.zatarox.vertx.async.api.BiHandler; 24 | import io.zatarox.vertx.async.api.Pair; 25 | import java.util.*; 26 | import java.util.concurrent.atomic.AtomicBoolean; 27 | import java.util.concurrent.atomic.AtomicInteger; 28 | import java.util.concurrent.atomic.AtomicReference; 29 | import java.util.stream.Stream; 30 | 31 | public final class AsyncCollectionsImpl implements AsyncCollections { 32 | 33 | private final Context context; 34 | 35 | public AsyncCollectionsImpl(final Context context) { 36 | this.context = context; 37 | } 38 | 39 | /** 40 | * Applies the function {@code consumer} to each item in {@code iterable}, 41 | * in parallel. The {@code consumer} is called with an item from the list, 42 | * and a callback when it has finished. If the {@code consumer} passes an 43 | * error to its {@code callback}, the main {@code handler} (for the 44 | * {@code each} function) is immediately called with the error. 45 | * 46 | * Note, that since this function applies {@code consumer} to each item in 47 | * parallel, there is no guarantee that the consumer functions will complete 48 | * in order. 49 | * 50 | * @param Define the manipulated type. 51 | * @param iterable A collection to iterate over. 52 | * @param consumer A function to apply to each item in {@code iterable}. The 53 | * iteratee is passed a {@code consumer} which must be called once it has 54 | * completed. If no error has occurred, the {@code callback} should be run 55 | * without arguments or with an explicit {@code null} argument. The array 56 | * index is not passed to the consumer. If you need the index, use 57 | * {@code eachOf}. 58 | * @param handler A callback which is called when all {@code consumer} 59 | * functions have finished, or an error occurs. 60 | */ 61 | @Override 62 | public void each(final Collection iterable, final BiHandler>> consumer, final Handler> handler) { 63 | if (iterable.isEmpty()) { 64 | handler.handle(DefaultAsyncResult.succeed()); 65 | } else { 66 | final AtomicBoolean stop = new AtomicBoolean(false); 67 | final AtomicInteger counter = new AtomicInteger(iterable.size()); 68 | iterable.stream().forEach(item -> { 69 | if (!stop.get()) { 70 | context.runOnContext(aVoid -> { 71 | try { 72 | consumer.handle(item, result -> { 73 | if (result.failed() || stop.get()) { 74 | if (!stop.get()) { 75 | stop.set(true); 76 | handler.handle(DefaultAsyncResult.fail(result)); 77 | } 78 | } else if (counter.decrementAndGet() == 0 && !stop.get()) { 79 | handler.handle(DefaultAsyncResult.succeed()); 80 | } 81 | }); 82 | } catch (Throwable ex) { 83 | if (!stop.get()) { 84 | stop.set(true); 85 | handler.handle(DefaultAsyncResult.fail(ex)); 86 | } 87 | } 88 | }); 89 | } 90 | }); 91 | } 92 | } 93 | 94 | /** 95 | * Like {@code each}, except that it passes the tuple key/value as argument 96 | * to the consumer. 97 | * 98 | * @param Define type of key. 99 | * @param Define type of value. 100 | * @param iterable A collection to iterate over. 101 | * @param consumer A function to apply to each item in {@code iterable}. The 102 | * {@code key} is the item's key. The iteratee is passed a {@code handler} 103 | * which must be called once it has completed. If no error has occurred, the 104 | * callback should be run without arguments or with an explicit {@code null} 105 | * argument. 106 | * @param handler A callback which is called when all {@code consumer} 107 | * functions have finished, or an error occurs. 108 | */ 109 | @Override 110 | public void each(final Map iterable, final BiHandler, Handler>> consumer, final Handler> handler) { 111 | if (iterable.isEmpty()) { 112 | handler.handle(DefaultAsyncResult.succeed()); 113 | } else { 114 | final AtomicBoolean stop = new AtomicBoolean(false); 115 | final AtomicInteger counter = new AtomicInteger(iterable.size()); 116 | iterable.entrySet().stream().forEach(item -> { 117 | context.runOnContext(aVoid -> { 118 | try { 119 | consumer.handle(new PairImpl<>(item.getKey(), item.getValue()), result -> { 120 | if (result.failed() || stop.get()) { 121 | if (!stop.get()) { 122 | stop.set(true); 123 | handler.handle(DefaultAsyncResult.fail(result)); 124 | } 125 | } else if (counter.decrementAndGet() == 0 && !stop.get()) { 126 | handler.handle(DefaultAsyncResult.succeed()); 127 | } 128 | }); 129 | } catch (Throwable ex) { 130 | handler.handle(DefaultAsyncResult.fail(ex)); 131 | } 132 | 133 | }); 134 | }); 135 | } 136 | } 137 | 138 | /** 139 | * Produces a new collection of values by mapping each value in 140 | * {@code iterable} through the {@code consumer} function. The 141 | * {@code consumer} is called with an item from {@code iterbale} and a 142 | * callback for when it has finished processing. Each of these callback 143 | * takes 2 arguments: an {@code error}, and the transformed item from 144 | * {@code iterable}. If {@code consumer} passes an error to its callback, 145 | * the main {@code handler} (for the {@code map} function) is immediately 146 | * called with the error. 147 | * 148 | * Note, that since this function applies the {@code consumer} to each item 149 | * in parallel, there is no guarantee that the {@code consumer} functions 150 | * will complete in order. However, the results array will be in the same 151 | * order as the original {@code iterable}. 152 | * 153 | * @param Define input type. 154 | * @param Define output type. 155 | * @param iterable A collection to iterate over. 156 | * @param consumer A function to apply to each item in {@code iterable}. The 157 | * iteratee is passed a {@code handler} which must be called once it has 158 | * completed with an error and a transformed item. Invoked with (item, 159 | * callback). 160 | * @param handler A callback which is called when all {@code consumer} 161 | * functions have finished, or an error occurs. Results is a List of the 162 | * transformed items from the {@code iterable}. 163 | */ 164 | @Override 165 | public void map(final List iterable, final BiHandler>> consumer, final Handler>> handler) { 166 | final List mapped = new ArrayList<>(iterable.size()); 167 | if (iterable.isEmpty()) { 168 | handler.handle(DefaultAsyncResult.succeed(mapped)); 169 | } else { 170 | final AtomicBoolean stop = new AtomicBoolean(false); 171 | final AtomicInteger counter = new AtomicInteger(iterable.size()); 172 | 173 | for (int i = 0; i < iterable.size(); i++) { 174 | final I item = iterable.get(i); 175 | final int pos = i; 176 | context.runOnContext(aVoid -> { 177 | try { 178 | consumer.handle(item, result -> { 179 | if (result.failed() || stop.get()) { 180 | if (!stop.get()) { 181 | stop.set(true); 182 | handler.handle(DefaultAsyncResult.fail(result)); 183 | } 184 | } else { 185 | mapped.add(pos, result.result()); 186 | if (counter.decrementAndGet() == 0 && !stop.get()) { 187 | handler.handle(DefaultAsyncResult.succeed(mapped)); 188 | } 189 | } 190 | }); 191 | } catch (Throwable ex) { 192 | if (!stop.get()) { 193 | stop.set(true); 194 | handler.handle(DefaultAsyncResult.fail(ex)); 195 | } 196 | } 197 | }); 198 | } 199 | } 200 | } 201 | 202 | /** 203 | * Returns a new collection of all the values in {@code iterable} which pass 204 | * an async truth test. This operation is performed in parallel, but the 205 | * results array will be in the same order as the original. 206 | * 207 | * @param Define the manipulated type. 208 | * @param iterable A collection to iterate over. 209 | * @param consumer A truth test to apply to each item in {@code iterable}. 210 | * The {@code consumer} is passed a {@code handler}, which must be called 211 | * with a boolean argument once it has completed. 212 | * @param handler A callback which is called after all the {@code consumer} 213 | * functions have finished. 214 | */ 215 | @Override 216 | public void filter(final Collection iterable, final BiHandler>> consumer, final Handler>> handler) { 217 | final List filtered = new LinkedList<>(); 218 | if (iterable.isEmpty()) { 219 | handler.handle(DefaultAsyncResult.succeed(filtered)); 220 | } else { 221 | final AtomicBoolean stop = new AtomicBoolean(false); 222 | final AtomicInteger counter = new AtomicInteger(iterable.size()); 223 | 224 | iterable.stream().forEach((item) -> { 225 | context.runOnContext(aVoid -> { 226 | try { 227 | consumer.handle(item, result -> { 228 | if (result.failed() || stop.get()) { 229 | if (!stop.get()) { 230 | stop.set(true); 231 | handler.handle(DefaultAsyncResult.fail(result)); 232 | } 233 | } else { 234 | if (result.result()) { 235 | filtered.add(item); 236 | } 237 | if (counter.decrementAndGet() == 0 && !stop.get()) { 238 | handler.handle(DefaultAsyncResult.succeed(filtered)); 239 | } 240 | } 241 | }); 242 | } catch (Throwable ex) { 243 | if (!stop.get()) { 244 | stop.set(true); 245 | handler.handle(DefaultAsyncResult.fail(ex)); 246 | } 247 | } 248 | }); 249 | }); 250 | } 251 | } 252 | 253 | /** 254 | * The opposite of {@code filter}. Removes values that pass an {@code async} 255 | * truth test. 256 | * 257 | * @param Define the manipulated type. 258 | * @param iterable A collection to iterate over. 259 | * @param consumer A falsy test to apply to each item in {@code iterable}. 260 | * The {@code consumer} is passed a {@code handler}, which must be called 261 | * with a boolean argument once it has completed. 262 | * @param handler A callback which is called after all the {@code consumer} 263 | * functions have finished. 264 | */ 265 | @Override 266 | public void reject(final Collection iterable, final BiHandler>> consumer, final Handler>> handler) { 267 | filter(iterable, (t, u) -> { 268 | consumer.handle(t, event -> { 269 | if (event.succeeded()) { 270 | u.handle(DefaultAsyncResult.succeed(!event.result())); 271 | } else { 272 | u.handle(event); 273 | } 274 | }); 275 | }, handler); 276 | } 277 | 278 | /** 279 | * A relative of {@code reduce}. Takes a Collection, and iterates over each 280 | * element in series, each step potentially mutating an {@code accumulator} 281 | * value. The type of the accumulator defaults to the type of collection 282 | * passed in. 283 | * 284 | * @param Define the type of input data 285 | * @param Define the type of output data 286 | * @param iterable A collection to iterate over. 287 | * @param consumer A function applied to each item in the collection that 288 | * potentially modifies the accumulator. The {@code consumer} is passed a 289 | * {@code handler}. If an error is passed to the callback, the transform is 290 | * stopped and the main {@code handler} is immediately called with the 291 | * error. 292 | * @param handler A callback which is called after all the {@code consumer} 293 | * functions have finished. Result is the transformed accumulator. 294 | */ 295 | @Override 296 | public void transform(final Collection iterable, final BiHandler>> consumer, final Handler>> handler) { 297 | context.runOnContext(new Handler() { 298 | final Iterator iterator = iterable.iterator(); 299 | final List result = new ArrayList<>(iterable.size()); 300 | 301 | @Override 302 | public void handle(Void event) { 303 | if (!iterator.hasNext()) { 304 | handler.handle(DefaultAsyncResult.succeed(result)); 305 | } else { 306 | try { 307 | consumer.handle(iterator.next(), event1 -> { 308 | if (event1.succeeded()) { 309 | result.add(event1.result()); 310 | context.runOnContext(this); 311 | } else { 312 | handler.handle(DefaultAsyncResult.fail(event1)); 313 | } 314 | }); 315 | } catch (Throwable ex) { 316 | handler.handle(DefaultAsyncResult.fail(ex)); 317 | } 318 | } 319 | } 320 | }); 321 | } 322 | 323 | /** 324 | * A relative of {@code reduce}. Takes a Map, and iterates over each element 325 | * in series, each step potentially mutating an {@code accumulator} value. 326 | * The type of the accumulator defaults to the type of collection passed in. 327 | * 328 | * @param Define the type of input key. 329 | * @param Define the type of input value. 330 | * @param Define the type of output key. 331 | * @param Define the type of output value. 332 | * @param iterable A collection to iterate over. 333 | * @param consumer A function applied to each item in the collection that 334 | * potentially modifies the accumulator. The {@code consumer} is passed a 335 | * {@code handler}. If an error is passed to the callback, the transform is 336 | * stopped and the main {@code handler} is immediately called with the 337 | * error. 338 | * @param handler A callback which is called after all the {@code consumer} 339 | * functions have finished. Result is the transformed accumulator. 340 | */ 341 | @Override 342 | public void transform(final Map iterable, final BiHandler, Handler>>> consumer, final Handler>> handler) { 343 | context.runOnContext(new Handler() { 344 | final Iterator> iterator = iterable.entrySet().iterator(); 345 | final Map results = new HashMap<>(iterable.size()); 346 | 347 | @Override 348 | public void handle(Void event) { 349 | if (!iterator.hasNext()) { 350 | handler.handle(DefaultAsyncResult.succeed(results)); 351 | } else { 352 | final Map.Entry item = iterator.next(); 353 | try { 354 | consumer.handle(new PairImpl<>(item.getKey(), item.getValue()), event1 -> { 355 | if (event1.succeeded()) { 356 | results.put(event1.result().getKey(), event1.result().getValue()); 357 | context.runOnContext(this); 358 | } else { 359 | handler.handle(DefaultAsyncResult.fail(event1)); 360 | } 361 | }); 362 | } catch (Throwable ex) { 363 | handler.handle(DefaultAsyncResult.fail(ex)); 364 | } 365 | } 366 | } 367 | }); 368 | } 369 | 370 | /** 371 | * Reduces {@code collection} into a single value using an async 372 | * {@code consumer} to return each successive step. {@code memo} is the 373 | * initial state of the reduction. This function only operates in series. 374 | * 375 | * This function is for situations where each step in the reduction needs to 376 | * be async; if you can get the data before reducing it, then it's probably 377 | * a good idea to do so. 378 | * 379 | * @param Define the type of input data 380 | * @param Define the type of output data 381 | * @param collection A collection to iterate over. 382 | * @param memo Initial state of the reduction. 383 | * @param function A function applied to each item in the array to produce 384 | * the next step in the reduction. The {@code function} is passed a 385 | * {@code handler} which accepts an optional error as its first argument, 386 | * and the state of the reduction as the second. If an error is passed to 387 | * the callback, the reduction is stopped and the main {@code handler} is 388 | * immediately called. 389 | * @param handler A callback which is called after all the {@code function} 390 | * functions have finished. Result is the transformed accumulator. 391 | */ 392 | @Override 393 | public void reduce(final Collection collection, final O memo, final BiHandler, Handler>> function, final Handler> handler) { 394 | context.runOnContext(new Handler() { 395 | final Iterator iterator = collection.iterator(); 396 | final AtomicReference value = new AtomicReference<>(memo); 397 | 398 | @Override 399 | public void handle(Void event) { 400 | if (!iterator.hasNext()) { 401 | handler.handle(DefaultAsyncResult.succeed(value.get())); 402 | } else { 403 | try { 404 | function.handle(new PairImpl<>(iterator.next(), value.get()), event1 -> { 405 | if (event1.failed()) { 406 | handler.handle(DefaultAsyncResult.fail(event1)); 407 | } else { 408 | value.set(event1.result()); 409 | context.runOnContext(this); 410 | } 411 | }); 412 | } catch (Throwable ex) { 413 | handler.handle(DefaultAsyncResult.fail(ex)); 414 | } 415 | } 416 | } 417 | }); 418 | } 419 | 420 | /** 421 | * Returns the first value in {@code collection} that passes an async truth 422 | * test. The {@code function} is applied in parallel, meaning the first 423 | * iteratee to return {@code true} will fire the detect {@code callback} 424 | * with that result. That means the result might not be the first item in 425 | * the original {@code collection} (in terms of order) that passes the test. 426 | * 427 | * @param Define the manipulated type. 428 | * @param collection A collection to iterate over. 429 | * @param function A truth test to apply to each item in {@code collection}. 430 | * The iteratee is passed a {@code callback} which must be called with a 431 | * boolean argument once it has completed. 432 | * @param handler A callback which is called as soon as any iteratee returns 433 | * {@code true}, or after all the {@code function} functions have finished. 434 | * Result will be the first item in the array that passes the truth test 435 | * (function) or the value {@code null} if none passed. 436 | */ 437 | @Override 438 | public void detect(final Collection collection, final BiHandler>> function, final Handler> handler) { 439 | if (collection.isEmpty()) { 440 | handler.handle(DefaultAsyncResult.succeed(null)); 441 | } else { 442 | final AtomicBoolean stop = new AtomicBoolean(false); 443 | final AtomicInteger counter = new AtomicInteger(collection.size()); 444 | collection.stream().forEach(item -> { 445 | context.runOnContext(aVoid -> { 446 | try { 447 | function.handle(item, event -> { 448 | if (event.succeeded()) { 449 | if (event.result() || stop.get()) { 450 | if (!stop.get()) { 451 | stop.set(true); 452 | handler.handle(DefaultAsyncResult.succeed(item)); 453 | } 454 | } else if (counter.decrementAndGet() == 0 && !stop.get()) { 455 | handler.handle(DefaultAsyncResult.succeed(null)); 456 | } 457 | } else if (!stop.get()) { 458 | stop.set(true); 459 | handler.handle(DefaultAsyncResult.fail(event)); 460 | } 461 | }); 462 | } catch (Throwable ex) { 463 | if (!stop.get()) { 464 | stop.set(true); 465 | handler.handle(DefaultAsyncResult.fail(ex)); 466 | } 467 | } 468 | }); 469 | }); 470 | } 471 | } 472 | 473 | /** 474 | * Returns {@code true} if at least one element in the {@code collection} 475 | * satisfies an async test. If any iteratee call returns {@code true}, the 476 | * main {@code callback} is immediately called. 477 | * 478 | * @param Define the manipulated type. 479 | * @param collection A collection to iterate over. 480 | * @param function A truth test to apply to each item in the array in 481 | * parallel. 482 | * @param handler A callback which is called as soon as any iteratee returns 483 | * {@code true}, or after all the iteratee functions have finished. Result 484 | * will be either {@code true} or {@code false} depending on the values of 485 | * the async tests. 486 | */ 487 | @Override 488 | public void some(final Collection collection, final BiHandler>> function, final Handler> handler) { 489 | if (collection.isEmpty()) { 490 | handler.handle(DefaultAsyncResult.succeed(false)); 491 | } else { 492 | final AtomicBoolean stop = new AtomicBoolean(false); 493 | final AtomicInteger counter = new AtomicInteger(collection.size()); 494 | 495 | collection.stream().forEach(item -> { 496 | context.runOnContext(aVoid -> { 497 | try { 498 | function.handle(item, event -> { 499 | if (event.succeeded()) { 500 | // Prevent Unhandled exception in Netty 501 | if (null != event.result() && event.result() || stop.get()) { 502 | if (!stop.get()) { 503 | stop.set(true); 504 | handler.handle(DefaultAsyncResult.succeed(true)); 505 | } 506 | } else if (counter.decrementAndGet() == 0 && !stop.get()) { 507 | handler.handle(DefaultAsyncResult.succeed(false)); 508 | } 509 | } else if (!stop.get()) { 510 | stop.set(true); 511 | handler.handle(DefaultAsyncResult.fail(event)); 512 | } 513 | }); 514 | } catch (Throwable ex) { 515 | if (!stop.get()) { 516 | stop.set(true); 517 | handler.handle(DefaultAsyncResult.fail(ex)); 518 | } 519 | } 520 | }); 521 | }); 522 | } 523 | } 524 | 525 | /** 526 | * Returns {@code true} if every element in {@code collection} satisfies an 527 | * async test. If any iteratee call returns {@code false}, the main 528 | * {@code callback} is immediately called. 529 | * 530 | * @param Define the manipulated type. 531 | * @param collection A collection to iterate over. 532 | * @param function A truth test to apply to each item in the collection in 533 | * parallel. 534 | * @param handler A callback which is called after all the {code collection} 535 | * functions have finished. Result will be either {@code true} or 536 | * {@code false} depending on the values of the async tests. 537 | */ 538 | @Override 539 | public void every(final Collection collection, final BiHandler>> function, final Handler> handler) { 540 | if (collection.isEmpty()) { 541 | handler.handle(DefaultAsyncResult.succeed(false)); 542 | } else { 543 | final AtomicBoolean stop = new AtomicBoolean(false); 544 | final AtomicInteger counter = new AtomicInteger(collection.size()); 545 | collection.stream().forEach(item -> { 546 | context.runOnContext(aVoid -> { 547 | try { 548 | function.handle(item, event -> { 549 | if (event.succeeded()) { 550 | // Prevent Unhandled exception in Netty 551 | if (null != event.result() && !event.result() || stop.get()) { 552 | if (!stop.get()) { 553 | stop.set(true); 554 | handler.handle(DefaultAsyncResult.succeed(false)); 555 | } 556 | } else if (counter.decrementAndGet() == 0 && !stop.get()) { 557 | handler.handle(DefaultAsyncResult.succeed(true)); 558 | } 559 | } else { 560 | stop.set(true); 561 | handler.handle(DefaultAsyncResult.fail(event)); 562 | } 563 | }); 564 | } catch (Throwable ex) { 565 | if (!stop.get()) { 566 | stop.set(true); 567 | handler.handle(DefaultAsyncResult.fail(ex)); 568 | } 569 | } 570 | }); 571 | }); 572 | } 573 | } 574 | 575 | /** 576 | * Applies {@code consumer} to each item in {@code collection}, 577 | * concatenating the results. Returns the concatenated list. The 578 | * {@code iteratee}s are called in parallel, and the results are 579 | * concatenated as they return. There is no guarantee that the results array 580 | * will be returned in the original order of {@code collection} passed to 581 | * the {@code iteratee} function. 582 | * 583 | * @param Define input type. 584 | * @param Define output type. 585 | * @param iterable A collection to iterate over. 586 | * @param consumer A function to apply to each item in collection 587 | * @param handler A callback which is called after all the {@code iterable} 588 | * functions have finished, or an error occurs. 589 | */ 590 | @Override 591 | public void concat(final Collection iterable, final BiHandler>>> consumer, final Handler>> handler) { 592 | final List results = new ArrayList<>(iterable.size()); 593 | if (iterable.isEmpty()) { 594 | handler.handle(DefaultAsyncResult.succeed(results)); 595 | } else { 596 | final AtomicBoolean stop = new AtomicBoolean(false); 597 | final AtomicInteger counter = new AtomicInteger(iterable.size()); 598 | 599 | iterable.stream().forEach(item -> { 600 | context.runOnContext(aVoid -> { 601 | try { 602 | consumer.handle(item, result -> { 603 | if (result.failed() || stop.get()) { 604 | if (!stop.get()) { 605 | stop.set(true); 606 | handler.handle(DefaultAsyncResult.fail(result)); 607 | } 608 | } else { 609 | if (result.result() != null) { 610 | results.addAll(result.result()); 611 | } 612 | if (counter.decrementAndGet() == 0 && !stop.get()) { 613 | handler.handle(DefaultAsyncResult.succeed(results)); 614 | } 615 | } 616 | }); 617 | } catch (Throwable ex) { 618 | if (!stop.get()) { 619 | stop.set(true); 620 | handler.handle(DefaultAsyncResult.fail(ex)); 621 | } 622 | } 623 | }); 624 | }); 625 | } 626 | } 627 | 628 | /** 629 | * Sorts a list by the results of running each {@code collection} value 630 | * through the internal comparator. 631 | * 632 | * @param Define the manipulated type. 633 | * @param iterable A collection to iterate over. 634 | * @param handler A callback which is called after all the {@code iterable} 635 | * functions have finished, or an error occurs. Results is the items from 636 | * the original {@code collection} sorted by the values returned by the 637 | * {@code iterable} calls. 638 | */ 639 | @Override 640 | public void sort(final Collection iterable, final Handler>> handler) { 641 | sort(iterable, null, handler); 642 | } 643 | 644 | /** 645 | * Sorts a list by the results of running each {@code collection} value 646 | * through an async {@code comparator}. 647 | * 648 | * @param Define the manipulated type. 649 | * @param iterable A collection to iterate over. 650 | * @param comparator A function used as comparator. 651 | * @param handler A callback which is called after all {@code comparator} 652 | * functions have finished, or an error occurs. Results is the items from 653 | * the original {@code collection} sorted by the values returned by the 654 | * {@code comparator} calls. 655 | */ 656 | @Override 657 | public void sort(final Collection iterable, final Comparator comparator, final Handler>> handler) { 658 | context.runOnContext(event -> { 659 | try { 660 | Stream stream = iterable.parallelStream(); 661 | if (comparator != null) { 662 | stream = stream.sorted(comparator); 663 | } else { 664 | stream = stream.sorted(); 665 | } 666 | handler.handle(DefaultAsyncResult.succeed(new ArrayList<>(Arrays.asList((T[]) stream.toArray())))); 667 | } catch (Throwable ex) { 668 | handler.handle(DefaultAsyncResult.fail(ex)); 669 | } 670 | }); 671 | } 672 | } 673 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/AsyncFlowsImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 19 | import io.zatarox.vertx.async.api.AsyncWorker; 20 | import io.vertx.core.AsyncResult; 21 | import io.vertx.core.Context; 22 | import io.vertx.core.Handler; 23 | import io.zatarox.vertx.async.api.AsyncFlows; 24 | import io.zatarox.vertx.async.api.BiHandler; 25 | import java.util.*; 26 | import java.util.concurrent.atomic.AtomicBoolean; 27 | import java.util.concurrent.atomic.AtomicInteger; 28 | import java.util.concurrent.atomic.AtomicReference; 29 | import java.util.function.BooleanSupplier; 30 | 31 | public final class AsyncFlowsImpl implements AsyncFlows { 32 | 33 | private final Context context; 34 | 35 | public AsyncFlowsImpl(final Context context) { 36 | this.context = context; 37 | } 38 | 39 | @Override 40 | public void series(final Collection>>> tasks, final Handler>> handler) { 41 | context.runOnContext(new Handler() { 42 | final Iterator>>> iterator = tasks.iterator(); 43 | final List results = new ArrayList<>(tasks.size()); 44 | 45 | @Override 46 | public void handle(Void event) { 47 | if (!iterator.hasNext()) { 48 | handler.handle(DefaultAsyncResult.succeed(results)); 49 | } else { 50 | final Handler>> task = iterator.next(); 51 | 52 | final Handler> taskHandler = (result) -> { 53 | if (result.failed()) { 54 | handler.handle(DefaultAsyncResult.fail(result)); 55 | } else { 56 | results.add(result.result()); 57 | context.runOnContext(Void -> { 58 | context.runOnContext(this); 59 | }); 60 | } 61 | }; 62 | task.handle(taskHandler); 63 | } 64 | } 65 | }); 66 | } 67 | 68 | @Override 69 | public void retry(final AbstractRetryOptions options, final Handler>> task, final Handler> handler) { 70 | context.runOnContext(options.build(task, handler)); 71 | } 72 | 73 | @Override 74 | public void forever(final Handler>> task, final Handler> handler) { 75 | context.runOnContext(new Handler() { 76 | @Override 77 | public void handle(Void event) { 78 | try { 79 | task.handle(result -> { 80 | if (result.failed()) { 81 | handler.handle(DefaultAsyncResult.fail(result)); 82 | } else { 83 | context.runOnContext(this); 84 | } 85 | }); 86 | } catch (Throwable ex) { 87 | handler.handle(DefaultAsyncResult.fail(ex)); 88 | } 89 | } 90 | }); 91 | } 92 | 93 | @Override 94 | public void waterfall(final Iterable>>> tasks, final Handler> handler) { 95 | context.runOnContext(new Handler() { 96 | private final Iterator>>> iterator = tasks.iterator(); 97 | private final AtomicBoolean stop = new AtomicBoolean(); 98 | private I result = null; 99 | 100 | @Override 101 | public void handle(Void event) { 102 | if (iterator.hasNext()) { 103 | try { 104 | iterator.next().handle(result, event1 -> { 105 | if (event1.succeeded()) { 106 | result = (I) event1.result(); 107 | context.runOnContext(this); 108 | } else { 109 | stop.set(true); 110 | handler.handle(DefaultAsyncResult.fail(event1)); 111 | } 112 | }); 113 | } catch (Throwable ex) { 114 | if (!stop.get()) { 115 | stop.set(true); 116 | handler.handle(DefaultAsyncResult.fail(ex)); 117 | } 118 | } 119 | } else { 120 | handler.handle(DefaultAsyncResult.succeed(result)); 121 | } 122 | } 123 | }); 124 | } 125 | 126 | @Override 127 | public void parallel(final List>>> tasks, final Handler>> handler) { 128 | final List results = new ArrayList<>(tasks.size()); 129 | if (tasks.isEmpty()) { 130 | handler.handle(DefaultAsyncResult.succeed(results)); 131 | } else { 132 | final AtomicBoolean stop = new AtomicBoolean(false); 133 | final AtomicInteger counter = new AtomicInteger(tasks.size()); 134 | 135 | for (int i = 0; i < tasks.size(); i++) { 136 | final Handler>> task = tasks.get(i); 137 | final int pos = i; 138 | context.runOnContext(aVoid -> { 139 | try { 140 | task.handle(result -> { 141 | if (result.failed() || stop.get()) { 142 | if (!stop.get()) { 143 | stop.set(true); 144 | handler.handle(DefaultAsyncResult.fail(result)); 145 | } 146 | } else { 147 | results.add(pos, result.result()); 148 | if (counter.decrementAndGet() == 0 && !stop.get()) { 149 | handler.handle(DefaultAsyncResult.succeed(results)); 150 | } 151 | } 152 | }); 153 | } catch (Throwable ex) { 154 | if (!stop.get()) { 155 | stop.set(true); 156 | handler.handle(DefaultAsyncResult.fail(ex)); 157 | } 158 | } 159 | }); 160 | } 161 | } 162 | } 163 | 164 | @Override 165 | public void whilst(final BooleanSupplier tester, final Handler>> consumer, final Handler> handler) { 166 | context.runOnContext(new Handler() { 167 | final AtomicBoolean stop = new AtomicBoolean(false); 168 | 169 | @Override 170 | public void handle(Void e) { 171 | try { 172 | if (tester.getAsBoolean()) { 173 | consumer.handle(e1 -> { 174 | if (e1.succeeded()) { 175 | context.runOnContext(this); 176 | } else { 177 | stop.set(true); 178 | handler.handle(DefaultAsyncResult.fail(e1)); 179 | } 180 | }); 181 | } else if (!stop.get()) { 182 | handler.handle(DefaultAsyncResult.succeed()); 183 | } 184 | } catch (Throwable ex) { 185 | if (!stop.get()) { 186 | stop.set(true); 187 | handler.handle(DefaultAsyncResult.fail(ex)); 188 | } 189 | } 190 | } 191 | }); 192 | } 193 | 194 | @Override 195 | public void whilst(final Handler>> tester, final Handler>> consumer, final Handler> handler) { 196 | context.runOnContext(new Handler() { 197 | final AtomicBoolean stop = new AtomicBoolean(false); 198 | 199 | @Override 200 | public void handle(Void e) { 201 | try { 202 | tester.handle(event -> { 203 | if (event.succeeded()) { 204 | if (event.result()) { 205 | try { 206 | consumer.handle(e1 -> { 207 | if (e1.succeeded()) { 208 | context.runOnContext(this); 209 | } else { 210 | stop.set(true); 211 | handler.handle(DefaultAsyncResult.fail(e1)); 212 | } 213 | }); 214 | } catch (Throwable ex) { 215 | if (!stop.get()) { 216 | stop.set(true); 217 | handler.handle(DefaultAsyncResult.fail(ex)); 218 | } 219 | } 220 | } else { 221 | stop.set(true); 222 | handler.handle(DefaultAsyncResult.succeed()); 223 | } 224 | } else if (!stop.get()) { 225 | stop.set(true); 226 | handler.handle(DefaultAsyncResult.fail(event)); 227 | } 228 | }); 229 | } catch (Throwable ex) { 230 | if (!stop.get()) { 231 | stop.set(true); 232 | handler.handle(DefaultAsyncResult.fail(ex)); 233 | } 234 | } 235 | } 236 | }); 237 | } 238 | 239 | @Override 240 | public void until(final BooleanSupplier tester, final Handler>> consumer, final Handler> handler) { 241 | context.runOnContext(new Handler() { 242 | @Override 243 | public void handle(Void e) { 244 | try { 245 | consumer.handle(e1 -> { 246 | if (e1.succeeded()) { 247 | if (tester.getAsBoolean()) { 248 | context.runOnContext(this); 249 | } else { 250 | handler.handle(DefaultAsyncResult.succeed()); 251 | } 252 | } else { 253 | handler.handle(DefaultAsyncResult.fail(e1)); 254 | } 255 | }); 256 | } catch (Throwable ex) { 257 | handler.handle(DefaultAsyncResult.fail(ex)); 258 | } 259 | } 260 | }); 261 | } 262 | 263 | @Override 264 | public BiHandler>> seq(final BiHandler>>... functions) { 265 | return new BiHandler>>() { 266 | private final Iterator>>> iterator = Arrays.asList(functions).iterator(); 267 | private final AtomicReference>>> current = new AtomicReference(null); 268 | 269 | @Override 270 | public void handle(final I item, final Handler> handler) { 271 | if (iterator.hasNext()) { 272 | current.set(iterator.next()); 273 | context.runOnContext(e1 -> { 274 | try { 275 | current.get().handle(item, e2 -> { 276 | if (e2.succeeded()) { 277 | this.handle((I) e2.result(), handler); 278 | } else { 279 | handler.handle(DefaultAsyncResult.fail(e2)); 280 | } 281 | }); 282 | } catch (Throwable ex) { 283 | handler.handle(DefaultAsyncResult.fail(ex)); 284 | } 285 | }); 286 | } else { 287 | handler.handle(DefaultAsyncResult.succeed((O) item)); 288 | } 289 | } 290 | }; 291 | } 292 | 293 | @Override 294 | public void times(final int counter, final BiHandler>> consumer, final Handler>> handler) { 295 | final List mapped = new ArrayList<>(counter); 296 | if (counter < 1) { 297 | handler.handle(DefaultAsyncResult.succeed(mapped)); 298 | } else { 299 | final AtomicBoolean stop = new AtomicBoolean(false); 300 | final AtomicInteger execution = new AtomicInteger(counter); 301 | 302 | for (int i = 0; i < counter; i++) { 303 | final int pos = i; 304 | context.runOnContext(aVoid -> { 305 | try { 306 | consumer.handle(pos, result -> { 307 | if (result.failed() || stop.get()) { 308 | if (!stop.get()) { 309 | stop.set(true); 310 | handler.handle(DefaultAsyncResult.fail(result)); 311 | } 312 | } else { 313 | mapped.add(pos, result.result()); 314 | if (execution.decrementAndGet() < 1 && !stop.get()) { 315 | handler.handle(DefaultAsyncResult.succeed(mapped)); 316 | } 317 | } 318 | }); 319 | } catch (Throwable ex) { 320 | stop.set(true); 321 | handler.handle(DefaultAsyncResult.fail(ex)); 322 | } 323 | }); 324 | } 325 | } 326 | } 327 | 328 | @Override 329 | public void race(final Collection>>> tasks, final Handler> handler) { 330 | if (tasks.isEmpty()) { 331 | handler.handle(DefaultAsyncResult.succeed(null)); 332 | } else { 333 | final AtomicBoolean stop = new AtomicBoolean(false); 334 | tasks.stream().forEach(task -> { 335 | context.runOnContext(event -> { 336 | try { 337 | task.handle(result -> { 338 | if (!stop.get()) { 339 | stop.set(true); 340 | handler.handle(result); 341 | } 342 | }); 343 | } catch (Throwable ex) { 344 | if (!stop.get()) { 345 | stop.set(true); 346 | handler.handle(DefaultAsyncResult.fail(ex)); 347 | } 348 | } 349 | }); 350 | }); 351 | } 352 | } 353 | 354 | @Override 355 | public AsyncWorker createQueue(final BiHandler>> worker) { 356 | return new AsyncQueueImpl(worker); 357 | } 358 | 359 | @Override 360 | public AsyncWorker createCargo(final BiHandler>> worker) { 361 | return new AsyncCargoImpl(worker); 362 | } 363 | 364 | @Override 365 | public void each(final Collection>>> functions, final T args, final Handler> handler) { 366 | if (functions.isEmpty()) { 367 | handler.handle(DefaultAsyncResult.succeed()); 368 | } else { 369 | final AtomicBoolean stop = new AtomicBoolean(false); 370 | final AtomicInteger counter = new AtomicInteger(functions.size()); 371 | 372 | functions.stream().forEach(function -> { 373 | context.runOnContext(event -> { 374 | try { 375 | function.handle(args, result -> { 376 | if (result.failed() || stop.get()) { 377 | if (!stop.get()) { 378 | stop.set(true); 379 | handler.handle(DefaultAsyncResult.fail(result)); 380 | } 381 | } else if (counter.decrementAndGet() == 0 && !stop.get()) { 382 | handler.handle(DefaultAsyncResult.succeed()); 383 | } 384 | }); 385 | } catch (Throwable ex) { 386 | stop.set(true); 387 | handler.handle(DefaultAsyncResult.fail(ex)); 388 | } 389 | }); 390 | }); 391 | } 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/AsyncMemoizeImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.vertx.core.Vertx; 21 | import io.zatarox.vertx.async.api.AsyncMemoize; 22 | import io.zatarox.vertx.async.api.BiHandler; 23 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 24 | import java.util.Map; 25 | import java.util.concurrent.ConcurrentHashMap; 26 | 27 | public final class AsyncMemoizeImpl implements AsyncMemoize { 28 | 29 | private final Map cache = new ConcurrentHashMap<>(); 30 | private final BiHandler>> consumer; 31 | 32 | public AsyncMemoizeImpl(final BiHandler>> consumer) { 33 | this.consumer = consumer; 34 | } 35 | 36 | @Override 37 | public O get(I argument) { 38 | return cache.get(argument); 39 | } 40 | 41 | @Override 42 | public boolean unset(I argument) { 43 | return cache.remove(argument) != null; 44 | } 45 | 46 | @Override 47 | public void clear() { 48 | cache.clear(); 49 | } 50 | 51 | @Override 52 | public boolean isEmpty() { 53 | return cache.isEmpty(); 54 | } 55 | 56 | public void accept(I item, Handler> handler) { 57 | if (cache.containsKey(item)) { 58 | handler.handle(DefaultAsyncResult.succeed(cache.get(item))); 59 | } else { 60 | Vertx.currentContext().runOnContext(event -> { 61 | consumer.handle(item, event1 -> { 62 | if (event1.succeeded()) { 63 | cache.put(item, event1.result()); 64 | } 65 | handler.handle(event1); 66 | }); 67 | }); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/AsyncQueueImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.vertx.core.Vertx; 21 | import io.zatarox.vertx.async.api.BiHandler; 22 | import io.zatarox.vertx.async.api.Pair; 23 | import java.util.Deque; 24 | import java.util.concurrent.ConcurrentLinkedDeque; 25 | 26 | public final class AsyncQueueImpl extends AbstractWorkerImpl { 27 | 28 | private final BiHandler>> worker; 29 | private final Deque>>> tasks = new ConcurrentLinkedDeque(); 30 | 31 | public AsyncQueueImpl(final BiHandler>> worker) { 32 | this(worker, 5); 33 | } 34 | 35 | public AsyncQueueImpl(final BiHandler>> worker, final int concurrency) { 36 | super(concurrency); 37 | this.worker = worker; 38 | } 39 | 40 | public boolean add(final T task, final Handler> handler, final boolean top) { 41 | try { 42 | final Pair>> item = new PairImpl(task, handler); 43 | final boolean result; 44 | if (!top) { 45 | result = tasks.offer(item); 46 | } else { 47 | result = tasks.offerFirst(item); 48 | } 49 | return result; 50 | } finally { 51 | if (current.get() < 1 && !paused.get()) { 52 | Vertx.currentContext().runOnContext(this); 53 | } 54 | } 55 | } 56 | 57 | @Override 58 | public boolean isIdle() { 59 | return current.get() == 0 && tasks.isEmpty(); 60 | } 61 | 62 | @Override 63 | public void clear() { 64 | tasks.clear(); 65 | } 66 | 67 | public void handle(Void event) { 68 | if (tasks.isEmpty()) { 69 | fireEmptyPool(); 70 | } else if (current.get() < concurrency.get() && !paused.get()) { 71 | final Pair>> task = tasks.poll(); 72 | current.incrementAndGet(); 73 | Vertx.currentContext().runOnContext(event1 -> { 74 | worker.handle(task.getKey(), event2 -> { 75 | task.getValue().handle(event2); 76 | current.decrementAndGet(); 77 | this.handle(event); 78 | }); 79 | }); 80 | this.handle(event); 81 | } 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/AsyncResultHandlerWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 21 | 22 | public final class AsyncResultHandlerWrapper implements Handler> { 23 | 24 | private final Handler> handler; 25 | 26 | public AsyncResultHandlerWrapper(Handler> handler) { 27 | this.handler = handler; 28 | } 29 | 30 | @Override 31 | public void handle(AsyncResult asyncResult) { 32 | if (asyncResult.failed()) { 33 | handler.handle(DefaultAsyncResult.fail(asyncResult.cause())); 34 | } else { 35 | handler.handle(DefaultAsyncResult.succeed((T) asyncResult.result())); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/AsyncUtilsImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 19 | import io.zatarox.vertx.async.api.AsyncMemoize; 20 | import io.vertx.core.AsyncResult; 21 | import io.vertx.core.Context; 22 | import io.vertx.core.Handler; 23 | import io.zatarox.vertx.async.api.AsyncUtils; 24 | import io.zatarox.vertx.async.api.BiHandler; 25 | import java.util.concurrent.TimeUnit; 26 | import java.util.concurrent.TimeoutException; 27 | import java.util.concurrent.atomic.AtomicBoolean; 28 | import java.util.function.Function; 29 | 30 | public final class AsyncUtilsImpl implements AsyncUtils { 31 | 32 | private final Context context; 33 | 34 | public AsyncUtilsImpl(final Context context) { 35 | this.context = context; 36 | } 37 | 38 | @Override 39 | public void timeout(final Handler>> function, final TimeUnit unit, final long delay, final Handler> handler) { 40 | context.executeBlocking(futur -> { 41 | final AtomicBoolean timeout = new AtomicBoolean(false); 42 | final long timerHandler = context.owner().setTimer(unit.toMillis(delay), id -> { 43 | timeout.set(true); 44 | futur.fail(new TimeoutException()); 45 | }); 46 | function.handle(event -> { 47 | context.owner().cancelTimer(timerHandler); 48 | if (!timeout.get()) { 49 | handler.handle(event); 50 | } 51 | }); 52 | }, handler); 53 | } 54 | 55 | @Override 56 | public AsyncMemoize memoize(final BiHandler>> function) { 57 | return new AsyncMemoizeImpl(function); 58 | } 59 | 60 | @Override 61 | public Handler>> constant(final T value) { 62 | return handler -> { 63 | handler.handle(DefaultAsyncResult.succeed(value)); 64 | }; 65 | } 66 | 67 | @Override 68 | public BiHandler>> asyncify(final Function function) { 69 | return (item, handler) -> { 70 | try { 71 | handler.handle(DefaultAsyncResult.succeed(function.apply(item))); 72 | } catch (Throwable ex) { 73 | handler.handle(DefaultAsyncResult.fail(ex)); 74 | } 75 | }; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/LoopRetryOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.vertx.core.Vertx; 21 | import java.util.concurrent.atomic.AtomicLong; 22 | 23 | public final class LoopRetryOptions extends AbstractRetryOptions { 24 | 25 | public LoopRetryOptions(long tries) { 26 | super(tries); 27 | } 28 | 29 | @Override 30 | public Handler build(final Handler>> task, final Handler> handler) { 31 | return new Handler() { 32 | final AtomicLong counter = new AtomicLong(tries); 33 | 34 | @Override 35 | public void handle(Void event) { 36 | task.handle(event1 -> { 37 | if (event1.failed()) { 38 | if (counter.decrementAndGet() < 1) { 39 | handler.handle(event1); 40 | } else { 41 | Vertx.currentContext().runOnContext(this); 42 | } 43 | } else { 44 | handler.handle(event1); 45 | } 46 | }); 47 | } 48 | }; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/impl/PairImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.zatarox.vertx.async.api.Pair; 19 | import java.io.Serializable; 20 | 21 | public final class PairImpl implements Pair, Serializable { 22 | 23 | private final K key; 24 | private final V value; 25 | 26 | public PairImpl(K key, V value) { 27 | this.key = key; 28 | this.value = value; 29 | } 30 | 31 | @Override 32 | public K getKey() { 33 | return key; 34 | } 35 | 36 | @Override 37 | public V getValue() { 38 | return value; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/zatarox/vertx/async/utils/DefaultAsyncResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.utils; 17 | 18 | import io.vertx.core.AsyncResult; 19 | 20 | public final class DefaultAsyncResult implements AsyncResult { 21 | 22 | private final Throwable cause; 23 | private final T result; 24 | 25 | public DefaultAsyncResult(Throwable cause, T result) { 26 | this.cause = cause; 27 | this.result = result; 28 | } 29 | 30 | public static AsyncResult succeed(T result) { 31 | return new DefaultAsyncResult<>(null, result); 32 | } 33 | 34 | public static AsyncResult succeed() { 35 | return succeed(null); 36 | } 37 | 38 | public static AsyncResult fail(Throwable cause) { 39 | if (cause == null) { 40 | throw new IllegalArgumentException("cause argument cannot be null"); 41 | } 42 | 43 | return new DefaultAsyncResult<>(cause, null); 44 | } 45 | 46 | public static AsyncResult fail(AsyncResult result) { 47 | return fail(result.cause()); 48 | } 49 | 50 | @Override 51 | public T result() { 52 | return result; 53 | } 54 | 55 | @Override 56 | public Throwable cause() { 57 | return cause; 58 | } 59 | 60 | @Override 61 | public boolean succeeded() { 62 | return cause == null; 63 | } 64 | 65 | @Override 66 | public boolean failed() { 67 | return cause != null; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/samples/java/io/zatarox/vertx/async/collections/EachCollection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.collections; 17 | 18 | import io.vertx.core.*; 19 | import io.zatarox.vertx.async.AsyncFactorySingleton; 20 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 21 | import java.util.stream.Collectors; 22 | import java.util.stream.IntStream; 23 | 24 | public final class EachCollection { 25 | 26 | public static void main(String[] args) { 27 | AsyncFactorySingleton.getInstance().createCollections(Vertx.vertx().getOrCreateContext()) 28 | .each(IntStream.iterate(0, i -> i + 1).limit(100).boxed().collect(Collectors.toList()), (item, handler) -> { 29 | System.out.println("get " + item); 30 | handler.handle(DefaultAsyncResult.succeed()); 31 | }, e -> { 32 | System.out.println("done."); 33 | Vertx.currentContext().owner().close(); 34 | }); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/samples/java/io/zatarox/vertx/async/collections/EachMapCollection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.collections; 17 | 18 | import io.vertx.core.*; 19 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 20 | import io.zatarox.vertx.async.AsyncFactorySingleton; 21 | import java.util.function.Function; 22 | import java.util.stream.Collectors; 23 | import java.util.stream.IntStream; 24 | 25 | public final class EachMapCollection { 26 | 27 | public static void main(String[] args) { 28 | AsyncFactorySingleton.getInstance().createCollections(Vertx.vertx().getOrCreateContext()) 29 | .each(IntStream.iterate(0, i -> i + 1).limit(100).boxed().collect(Collectors.toMap(p -> p.toString(), Function.identity())), (item, handler) -> { 30 | System.out.println(item.getKey() + " -> " + item.getValue()); 31 | handler.handle(DefaultAsyncResult.succeed()); 32 | }, e -> { 33 | System.out.println("done."); 34 | Vertx.currentContext().owner().close(); 35 | }); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/integration/io/zatarox/vertx/async/AsyncFactorySingletonTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async; 17 | 18 | import io.vertx.ext.unit.TestContext; 19 | import io.vertx.ext.unit.junit.RunTestOnContext; 20 | import io.vertx.ext.unit.junit.VertxUnitRunner; 21 | import io.zatarox.vertx.async.api.*; 22 | import static org.junit.Assert.*; 23 | import org.junit.Rule; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | 27 | @RunWith(VertxUnitRunner.class) 28 | public final class AsyncFactorySingletonTest { 29 | 30 | @Rule 31 | public RunTestOnContext rule = new RunTestOnContext(); 32 | 33 | @Test 34 | public void onlyOneFactoryInstance(final TestContext context) { 35 | assertSame(AsyncFactorySingleton.getInstance(), AsyncFactorySingleton.getInstance()); 36 | } 37 | 38 | @Test 39 | public void differentAsyncFlowsInstance(final TestContext context) { 40 | final AsyncFlows instance1 = AsyncFactorySingleton.getInstance().createFlows(rule.vertx().getOrCreateContext()); 41 | final AsyncFlows instance2 = AsyncFactorySingleton.getInstance().createFlows(rule.vertx().getOrCreateContext()); 42 | assertNotSame(instance1, instance2); 43 | } 44 | 45 | @Test 46 | public void differentAsyncCollectionsInstance(final TestContext context) { 47 | final AsyncCollections instance1 = AsyncFactorySingleton.getInstance().createCollections(rule.vertx().getOrCreateContext()); 48 | final AsyncCollections instance2 = AsyncFactorySingleton.getInstance().createCollections(rule.vertx().getOrCreateContext()); 49 | assertNotSame(instance1, instance2); 50 | } 51 | 52 | @Test 53 | public void differentAsyncUtilsInstance(final TestContext context) { 54 | final AsyncUtils instance1 = AsyncFactorySingleton.getInstance().createUtils(rule.vertx().getOrCreateContext()); 55 | final AsyncUtils instance2 = AsyncFactorySingleton.getInstance().createUtils(rule.vertx().getOrCreateContext()); 56 | assertNotSame(instance1, instance2); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/fakes/FakeAsyncFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.fakes; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.zatarox.vertx.async.api.BiHandler; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public abstract class FakeAsyncFunction implements BiHandler>> { 26 | 27 | private final ArrayList consumedValues = new ArrayList<>(); 28 | private int runCount = 0; 29 | 30 | protected void incrementRunCount() { 31 | runCount++; 32 | } 33 | 34 | protected void addConsumedValue(T consumedValue) { 35 | this.consumedValues.add(consumedValue); 36 | } 37 | 38 | public int runCount() { 39 | return runCount; 40 | } 41 | 42 | public T consumedValue() { 43 | return consumedValues.get(consumedValues.size() - 1); 44 | } 45 | 46 | public List consumedValues() { 47 | return consumedValues; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/fakes/FakeAsyncSupplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.fakes; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | 21 | 22 | public abstract class FakeAsyncSupplier implements Handler>> { 23 | 24 | private int runCount = 0; 25 | 26 | protected void incrementRunCount() { 27 | runCount++; 28 | } 29 | 30 | public int runCount() { 31 | return runCount; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/fakes/FakeFailingAsyncFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.fakes; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 21 | 22 | public class FakeFailingAsyncFunction extends FakeAsyncFunction { 23 | 24 | private final int successCount; 25 | private final R result; 26 | private final RuntimeException cause; 27 | private final boolean catched; 28 | 29 | public FakeFailingAsyncFunction(RuntimeException cause) { 30 | this(cause, true); 31 | } 32 | 33 | public FakeFailingAsyncFunction(RuntimeException cause, boolean catched) { 34 | this(0, null, cause, catched); 35 | } 36 | 37 | public FakeFailingAsyncFunction(int successCount, R result, RuntimeException cause, boolean catched) { 38 | this.successCount = successCount; 39 | this.result = result; 40 | this.cause = cause; 41 | this.catched = catched; 42 | } 43 | 44 | @Override 45 | public void handle(T value, Handler> handler) { 46 | addConsumedValue(value); 47 | incrementRunCount(); 48 | 49 | if (runCount() > successCount) { 50 | if(catched) { 51 | handler.handle(DefaultAsyncResult.fail(cause)); 52 | } else { 53 | throw cause; 54 | } 55 | } else { 56 | handler.handle(DefaultAsyncResult.succeed(result)); 57 | } 58 | } 59 | 60 | public Throwable cause() { 61 | return cause; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/fakes/FakeFailingAsyncSupplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.fakes; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 21 | 22 | public class FakeFailingAsyncSupplier extends FakeAsyncSupplier { 23 | 24 | private final int successCount; 25 | private final T result; 26 | private final RuntimeException cause; 27 | private final boolean catched; 28 | 29 | public FakeFailingAsyncSupplier(RuntimeException cause) { 30 | this(0, null, cause); 31 | } 32 | 33 | public FakeFailingAsyncSupplier(RuntimeException cause, boolean catched) { 34 | this(0, null, cause, catched); 35 | } 36 | 37 | public FakeFailingAsyncSupplier(int successCount, T result, RuntimeException cause) { 38 | this(successCount, result, cause, true); 39 | } 40 | 41 | public FakeFailingAsyncSupplier(int successCount, T result, RuntimeException cause, boolean catched) { 42 | this.successCount = successCount; 43 | this.result = result; 44 | this.cause = cause; 45 | this.catched = catched; 46 | } 47 | 48 | @Override 49 | public void handle(Handler> handler) { 50 | incrementRunCount(); 51 | 52 | if (runCount() > successCount) { 53 | if(catched) { 54 | handler.handle(DefaultAsyncResult.fail(cause)); 55 | } else { 56 | throw cause; 57 | } 58 | } else { 59 | handler.handle(DefaultAsyncResult.succeed(result)); 60 | } 61 | } 62 | 63 | public Throwable cause() { 64 | return cause; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/fakes/FakeSuccessfulAsyncFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.fakes; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 21 | 22 | public class FakeSuccessfulAsyncFunction extends FakeAsyncFunction { 23 | 24 | private final int failureCount; 25 | private final R result; 26 | private final Throwable cause; 27 | 28 | public FakeSuccessfulAsyncFunction(R result) { 29 | this(0, null, result); 30 | } 31 | 32 | public FakeSuccessfulAsyncFunction(int failureCount, Throwable cause, R result) { 33 | this.failureCount = failureCount; 34 | this.result = result; 35 | this.cause = cause; 36 | } 37 | 38 | @Override 39 | public void handle(T value, Handler> handler) { 40 | addConsumedValue(value); 41 | incrementRunCount(); 42 | 43 | if (runCount() > failureCount) { 44 | handler.handle(DefaultAsyncResult.succeed(result)); 45 | } else { 46 | handler.handle(DefaultAsyncResult.fail(cause)); 47 | } 48 | } 49 | 50 | public R result() { 51 | return result; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/fakes/FakeSuccessfulAsyncSupplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.fakes; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 21 | 22 | public class FakeSuccessfulAsyncSupplier extends FakeAsyncSupplier { 23 | 24 | private final int failureCount; 25 | private final T result; 26 | private final Throwable cause; 27 | 28 | public FakeSuccessfulAsyncSupplier(T result) { 29 | this(0, null, result); 30 | } 31 | 32 | public FakeSuccessfulAsyncSupplier(int failureCount, Throwable cause, T result) { 33 | this.failureCount = failureCount; 34 | this.result = result; 35 | this.cause = cause; 36 | } 37 | 38 | @Override 39 | public void handle(Handler> handler) { 40 | incrementRunCount(); 41 | 42 | if (runCount() > failureCount) { 43 | handler.handle(DefaultAsyncResult.succeed(result)); 44 | } else { 45 | handler.handle(DefaultAsyncResult.fail(cause)); 46 | } 47 | } 48 | 49 | public T result() { 50 | return result; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/impl/AsyncCargoImplTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.vertx.ext.unit.Async; 21 | import io.vertx.ext.unit.TestContext; 22 | import io.vertx.ext.unit.junit.Repeat; 23 | import io.vertx.ext.unit.junit.RepeatRule; 24 | import io.vertx.ext.unit.junit.RunTestOnContext; 25 | import io.vertx.ext.unit.junit.VertxUnitRunner; 26 | import io.zatarox.vertx.async.AsyncFactorySingleton; 27 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 28 | import java.util.concurrent.atomic.AtomicBoolean; 29 | import java.util.concurrent.atomic.AtomicInteger; 30 | import org.junit.Before; 31 | import org.junit.Rule; 32 | import org.junit.Test; 33 | import org.junit.runner.RunWith; 34 | import io.zatarox.vertx.async.api.AsyncWorkerListener; 35 | import io.zatarox.vertx.async.api.AsyncWorker; 36 | import io.zatarox.vertx.async.api.BiHandler; 37 | import io.zatarox.vertx.async.api.Pair; 38 | import java.util.Arrays; 39 | import java.util.Collection; 40 | import org.mockito.junit.MockitoJUnit; 41 | import org.mockito.junit.MockitoRule; 42 | 43 | @RunWith(VertxUnitRunner.class) 44 | public final class AsyncCargoImplTest { 45 | 46 | /** 47 | * Limits 48 | */ 49 | private static final int TIMEOUT_LIMIT = 1000; 50 | private static final int REPEAT_LIMIT = 100; 51 | 52 | private BiHandler>>>, Handler>> worker; 53 | private AsyncCargoImpl cargo; 54 | 55 | @Rule 56 | public RepeatRule repeater = new RepeatRule(); 57 | @Rule 58 | public RunTestOnContext rule = new RunTestOnContext(); 59 | @Rule 60 | public MockitoRule mockito = MockitoJUnit.rule(); 61 | 62 | @Before 63 | public void setUp(final TestContext context) { 64 | worker = (Collection>>> items, Handler> handler) -> { 65 | AsyncFactorySingleton.getInstance().createCollections(rule.vertx().getOrCreateContext()).each(items, (item, callback) -> { 66 | rule.vertx().setTimer(item.getKey(), event -> { 67 | item.getValue().handle(DefaultAsyncResult.succeed()); 68 | }); 69 | callback.handle(DefaultAsyncResult.succeed()); 70 | }, handler); 71 | }; 72 | cargo = new AsyncCargoImpl(worker, 5); 73 | context.assertNotNull(cargo); 74 | context.assertEquals(0, cargo.getRunning()); 75 | context.assertEquals(5, cargo.getConcurrency()); 76 | } 77 | 78 | @Test(timeout = AsyncCargoImplTest.TIMEOUT_LIMIT) 79 | @Repeat(value = AsyncCargoImplTest.REPEAT_LIMIT, silent = true) 80 | public void executeEmptyCargo(final TestContext context) { 81 | context.assertTrue(cargo.isIdle()); 82 | rule.vertx().runOnContext(cargo); 83 | context.assertEquals(0, cargo.getRunning()); 84 | } 85 | 86 | @Test(expected = IllegalArgumentException.class) 87 | public void testNegativeConcurrency() { 88 | cargo.setConcurrency(0); 89 | } 90 | 91 | @Test(timeout = AsyncCargoImplTest.TIMEOUT_LIMIT) 92 | @Repeat(value = AsyncCargoImplTest.REPEAT_LIMIT, silent = true) 93 | public void testListeners(final TestContext context) { 94 | final Async async = context.async(); 95 | final AtomicBoolean empty = new AtomicBoolean(false); 96 | final AtomicBoolean full = new AtomicBoolean(false); 97 | final AsyncWorkerListener listener = new AsyncWorkerListener() { 98 | @Override 99 | public void poolEmpty(AsyncWorker instance) { 100 | context.assertNotNull(instance); 101 | empty.set(true); 102 | context.assertTrue(instance.remove(this)); 103 | context.assertFalse(instance.remove(this)); 104 | async.complete(); 105 | } 106 | 107 | @Override 108 | public void poolFull(AsyncWorker instance) { 109 | full.set(true); 110 | } 111 | }; 112 | context.assertTrue(cargo.add(listener)); 113 | context.assertFalse(cargo.add(listener)); 114 | cargo.add(Arrays.asList(100), event -> { 115 | context.assertTrue(event.succeeded()); 116 | context.assertTrue(empty.get()); 117 | context.assertTrue(full.get()); 118 | }, false); 119 | context.assertFalse(cargo.isIdle()); 120 | } 121 | 122 | @Test(timeout = AsyncCargoImplTest.TIMEOUT_LIMIT) 123 | @Repeat(value = AsyncCargoImplTest.REPEAT_LIMIT, silent = true) 124 | public void executeOneTaskSucceedInCargo(final TestContext context) { 125 | final Async async = context.async(); 126 | context.assertTrue(cargo.add(Arrays.asList(100), event -> { 127 | context.assertTrue(event.succeeded()); 128 | async.complete(); 129 | }, false)); 130 | context.assertFalse(cargo.isIdle()); 131 | } 132 | 133 | @Test(timeout = AsyncCargoImplTest.TIMEOUT_LIMIT) 134 | @Repeat(value = AsyncCargoImplTest.REPEAT_LIMIT, silent = true) 135 | public void executeTwoTaskSucceedWithOneWorker(final TestContext context) { 136 | final Async async = context.async(); 137 | @SuppressWarnings("LocalVariableHidesMemberVariable") 138 | final AtomicInteger counter = new AtomicInteger(); 139 | final AsyncCargoImpl queue = new AsyncCargoImpl(worker, 1); 140 | context.assertTrue(queue.add(Arrays.asList(100, 200), event -> { 141 | context.assertTrue(event.succeeded()); 142 | context.assertTrue(counter.incrementAndGet() <= 2); 143 | if (counter.get() == 2) { 144 | async.complete(); 145 | } 146 | }, false)); 147 | context.assertFalse(queue.isIdle()); 148 | } 149 | 150 | @Test(timeout = AsyncCargoImplTest.TIMEOUT_LIMIT) 151 | @Repeat(value = AsyncCargoImplTest.REPEAT_LIMIT, silent = true) 152 | public void executeTwoTaskSucceedWithDefaultNumberWorkers(final TestContext context) { 153 | final Async async = context.async(); 154 | final AtomicInteger counter = new AtomicInteger(); 155 | context.assertTrue(cargo.add(Arrays.asList(100, 200), event -> { 156 | context.assertTrue(event.succeeded()); 157 | context.assertTrue(counter.incrementAndGet() <= 2); 158 | if (counter.get() == 2) { 159 | async.complete(); 160 | } 161 | }, false)); 162 | context.assertFalse(cargo.isIdle()); 163 | } 164 | 165 | @Test(timeout = AsyncCargoImplTest.TIMEOUT_LIMIT) 166 | @Repeat(value = AsyncCargoImplTest.REPEAT_LIMIT, silent = true) 167 | public void executeOneTaskFailedInCargo(final TestContext context) { 168 | final Async async = context.async(); 169 | cargo = new AsyncCargoImpl<>((tasks, handler) -> { 170 | AsyncFactorySingleton.getInstance().createCollections(rule.vertx().getOrCreateContext()).each(tasks, (task, callback) -> { 171 | task.getValue().handle(DefaultAsyncResult.fail(new IllegalArgumentException())); 172 | callback.handle(DefaultAsyncResult.fail(new IllegalArgumentException())); 173 | }, handler); 174 | }); 175 | context.assertTrue(cargo.add(Arrays.asList(100), event -> { 176 | context.assertFalse(event.succeeded()); 177 | context.assertTrue(event.cause() instanceof IllegalArgumentException); 178 | async.complete(); 179 | }, false)); 180 | context.assertFalse(cargo.isIdle()); 181 | } 182 | 183 | @Test(timeout = AsyncCargoImplTest.TIMEOUT_LIMIT) 184 | @Repeat(value = AsyncCargoImplTest.REPEAT_LIMIT, silent = true) 185 | public void executePauseAndUnpause(final TestContext context) { 186 | final Async async = context.async(); 187 | final AtomicInteger counter = new AtomicInteger(); 188 | cargo.setPaused(true); 189 | context.assertTrue(cargo.isPaused()); 190 | context.assertTrue(cargo.isIdle()); 191 | context.assertTrue(cargo.add(Arrays.asList(100, 200), event -> { 192 | context.assertTrue(event.succeeded()); 193 | context.assertFalse(cargo.isPaused()); 194 | context.assertTrue(counter.incrementAndGet() <= 2); 195 | if (counter.get() == 2) { 196 | async.complete(); 197 | } 198 | }, false)); 199 | context.assertEquals(0, cargo.getRunning()); 200 | context.assertFalse(cargo.isIdle()); 201 | cargo.setPaused(false); 202 | context.assertFalse(cargo.isIdle()); 203 | } 204 | 205 | @Test(timeout = AsyncCargoImplTest.TIMEOUT_LIMIT) 206 | @Repeat(value = AsyncCargoImplTest.REPEAT_LIMIT, silent = true) 207 | public void executeAddToTop(final TestContext context) { 208 | final Async async = context.async(); 209 | final AtomicInteger counter = new AtomicInteger(); 210 | cargo = new AsyncCargoImpl(worker, 1); 211 | cargo.setPaused(true); 212 | context.assertTrue(cargo.add(Arrays.asList(200, 100), event -> { 213 | context.assertTrue(event.succeeded()); 214 | context.assertFalse(cargo.isPaused()); 215 | context.assertTrue(counter.incrementAndGet() <= 2); 216 | if (counter.get() == 2) { 217 | async.complete(); 218 | } 219 | }, true)); 220 | context.assertEquals(0, cargo.getRunning()); 221 | context.assertFalse(cargo.isIdle()); 222 | cargo.setPaused(false); 223 | context.assertFalse(cargo.isIdle()); 224 | } 225 | 226 | @Test(timeout = AsyncCargoImplTest.TIMEOUT_LIMIT) 227 | @Repeat(value = AsyncCargoImplTest.REPEAT_LIMIT, silent = true) 228 | public void executeClear(final TestContext context) { 229 | final Async async = context.async(); 230 | final AtomicInteger counter = new AtomicInteger(); 231 | cargo.setPaused(true); 232 | context.assertTrue(cargo.add(Arrays.asList(200), event -> { 233 | context.fail(); 234 | }, false)); 235 | context.assertEquals(0, cargo.getRunning()); 236 | context.assertFalse(cargo.isIdle()); 237 | cargo.clear(); 238 | cargo.setPaused(false); 239 | context.assertTrue(cargo.add(Arrays.asList(100), event -> { 240 | context.assertTrue(event.succeeded()); 241 | context.assertFalse(cargo.isPaused()); 242 | context.assertEquals(1, counter.incrementAndGet()); 243 | async.complete(); 244 | }, false)); 245 | } 246 | 247 | } 248 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/impl/AsyncMemoizeImplTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.ext.unit.Async; 19 | import io.vertx.ext.unit.TestContext; 20 | import io.vertx.ext.unit.junit.Repeat; 21 | import io.vertx.ext.unit.junit.RepeatRule; 22 | import io.vertx.ext.unit.junit.RunTestOnContext; 23 | import io.vertx.ext.unit.junit.VertxUnitRunner; 24 | import io.zatarox.vertx.async.AsyncFactorySingleton; 25 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 26 | import java.util.concurrent.atomic.AtomicInteger; 27 | import org.junit.Rule; 28 | import org.junit.Test; 29 | import org.junit.runner.RunWith; 30 | import org.mockito.junit.MockitoJUnit; 31 | import org.mockito.junit.MockitoRule; 32 | 33 | @RunWith(VertxUnitRunner.class) 34 | public final class AsyncMemoizeImplTest { 35 | 36 | /** 37 | * Limits 38 | */ 39 | private static final int TIMEOUT_LIMIT = 1000; 40 | private static final int REPEAT_LIMIT = 100; 41 | 42 | @Rule 43 | public RepeatRule repeater = new RepeatRule(); 44 | @Rule 45 | public RunTestOnContext rule = new RunTestOnContext(); 46 | @Rule 47 | public MockitoRule mockito = MockitoJUnit.rule(); 48 | 49 | @Test(timeout = AsyncMemoizeImplTest.TIMEOUT_LIMIT) 50 | @Repeat(value = AsyncMemoizeImplTest.REPEAT_LIMIT, silent = true) 51 | public void executeSucceedAndClear(final TestContext context) { 52 | final Async async = context.async(); 53 | final AtomicInteger counter = new AtomicInteger(0); 54 | final AsyncMemoizeImpl memoize = new AsyncMemoizeImpl<>((item, handler) -> { 55 | counter.incrementAndGet(); 56 | handler.handle(DefaultAsyncResult.succeed(item + 1)); 57 | }); 58 | 59 | context.assertTrue(memoize.isEmpty()); 60 | memoize.accept(1, event -> { 61 | context.assertTrue(event.succeeded()); 62 | context.assertFalse(memoize.isEmpty()); 63 | context.assertEquals(2, memoize.get(1)); 64 | context.assertEquals(1, counter.get()); 65 | memoize.clear(); 66 | context.assertTrue(memoize.isEmpty()); 67 | async.complete(); 68 | }); 69 | } 70 | 71 | @Test(timeout = AsyncMemoizeImplTest.TIMEOUT_LIMIT) 72 | @Repeat(value = AsyncMemoizeImplTest.REPEAT_LIMIT, silent = true) 73 | public void executeSucceedAndUnset(final TestContext context) { 74 | final Async async = context.async(); 75 | final AtomicInteger counter = new AtomicInteger(0); 76 | final AsyncMemoizeImpl memoize = new AsyncMemoizeImpl<>((item, handler) -> { 77 | counter.incrementAndGet(); 78 | handler.handle(DefaultAsyncResult.succeed(item + 1)); 79 | }); 80 | 81 | context.assertTrue(memoize.isEmpty()); 82 | memoize.accept(1, event -> { 83 | context.assertTrue(event.succeeded()); 84 | context.assertFalse(memoize.isEmpty()); 85 | context.assertEquals(2, memoize.get(1)); 86 | context.assertEquals(1, counter.get()); 87 | context.assertTrue(memoize.unset(1)); 88 | context.assertFalse(memoize.unset(1)); 89 | context.assertTrue(memoize.isEmpty()); 90 | async.complete(); 91 | }); 92 | } 93 | 94 | @Test(timeout = AsyncMemoizeImplTest.TIMEOUT_LIMIT) 95 | @Repeat(value = AsyncMemoizeImplTest.REPEAT_LIMIT, silent = true) 96 | public void executeSucceedAndTestCache(final TestContext context) { 97 | final Async async = context.async(); 98 | final AtomicInteger counter = new AtomicInteger(0); 99 | final AsyncMemoizeImpl memoize = new AsyncMemoizeImpl<>((item, handler) -> { 100 | counter.incrementAndGet(); 101 | handler.handle(DefaultAsyncResult.succeed(item + 1)); 102 | }); 103 | 104 | context.assertTrue(memoize.isEmpty()); 105 | AsyncFactorySingleton.getInstance().createFlows(rule.vertx().getOrCreateContext()).seq((t, u) -> { 106 | memoize.accept(1, event -> { 107 | context.assertTrue(event.succeeded()); 108 | context.assertFalse(memoize.isEmpty()); 109 | context.assertEquals(2, memoize.get(1)); 110 | context.assertEquals(1, counter.get()); 111 | u.handle(DefaultAsyncResult.succeed()); 112 | }); 113 | }, (t, u) -> { 114 | memoize.accept(1, event -> { 115 | context.assertTrue(event.succeeded()); 116 | context.assertFalse(memoize.isEmpty()); 117 | context.assertEquals(2, memoize.get(1)); 118 | context.assertEquals(1, counter.get()); 119 | context.assertTrue(memoize.unset(1)); 120 | context.assertFalse(memoize.unset(1)); 121 | context.assertTrue(memoize.isEmpty()); 122 | u.handle(DefaultAsyncResult.succeed()); 123 | }); 124 | }).handle(null, event -> { 125 | async.complete(); 126 | }); 127 | } 128 | 129 | @Test(timeout = AsyncMemoizeImplTest.TIMEOUT_LIMIT) 130 | @Repeat(value = AsyncMemoizeImplTest.REPEAT_LIMIT, silent = true) 131 | public void executeFailedAndClear(final TestContext context) { 132 | final Async async = context.async(); 133 | final AtomicInteger counter = new AtomicInteger(0); 134 | final AsyncMemoizeImpl memoize = new AsyncMemoizeImpl<>((item, handler) -> { 135 | counter.incrementAndGet(); 136 | handler.handle(DefaultAsyncResult.fail(new IllegalArgumentException())); 137 | }); 138 | memoize.accept(1, event -> { 139 | context.assertFalse(event.succeeded()); 140 | context.assertTrue(memoize.isEmpty()); 141 | context.assertNull(memoize.get(1)); 142 | context.assertEquals(1, counter.get()); 143 | memoize.clear(); 144 | context.assertTrue(memoize.isEmpty()); 145 | async.complete(); 146 | }); 147 | } 148 | 149 | @Test(timeout = AsyncMemoizeImplTest.TIMEOUT_LIMIT) 150 | @Repeat(value = AsyncMemoizeImplTest.REPEAT_LIMIT, silent = true) 151 | public void executeFailedAndUnset(final TestContext context) { 152 | final Async async = context.async(); 153 | final AtomicInteger counter = new AtomicInteger(0); 154 | final AsyncMemoizeImpl memoize = new AsyncMemoizeImpl<>((item, handler) -> { 155 | counter.incrementAndGet(); 156 | handler.handle(DefaultAsyncResult.fail(new IllegalArgumentException())); 157 | }); 158 | 159 | context.assertTrue(memoize.isEmpty()); 160 | memoize.accept(1, event -> { 161 | context.assertFalse(event.succeeded()); 162 | context.assertTrue(memoize.isEmpty()); 163 | context.assertNull(memoize.get(1)); 164 | context.assertEquals(1, counter.get()); 165 | context.assertTrue(memoize.isEmpty()); 166 | context.assertFalse(memoize.unset(1)); 167 | context.assertTrue(memoize.isEmpty()); 168 | async.complete(); 169 | }); 170 | } 171 | 172 | } 173 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/impl/AsyncQueueImplTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.vertx.ext.unit.Async; 21 | import io.vertx.ext.unit.TestContext; 22 | import io.vertx.ext.unit.junit.Repeat; 23 | import io.vertx.ext.unit.junit.RepeatRule; 24 | import io.vertx.ext.unit.junit.RunTestOnContext; 25 | import io.vertx.ext.unit.junit.VertxUnitRunner; 26 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 27 | import java.util.concurrent.atomic.AtomicBoolean; 28 | import java.util.concurrent.atomic.AtomicInteger; 29 | import org.junit.Before; 30 | import org.junit.Rule; 31 | import org.junit.Test; 32 | import org.junit.runner.RunWith; 33 | import io.zatarox.vertx.async.api.AsyncWorkerListener; 34 | import io.zatarox.vertx.async.api.AsyncWorker; 35 | import io.zatarox.vertx.async.api.BiHandler; 36 | import org.mockito.junit.MockitoJUnit; 37 | import org.mockito.junit.MockitoRule; 38 | 39 | @RunWith(VertxUnitRunner.class) 40 | public final class AsyncQueueImplTest { 41 | 42 | /** 43 | * Limits 44 | */ 45 | private static final int TIMEOUT_LIMIT = 1000; 46 | private static final int REPEAT_LIMIT = 100; 47 | 48 | private BiHandler>> worker; 49 | private AsyncQueueImpl queue; 50 | 51 | @Rule 52 | public RepeatRule repeater = new RepeatRule(); 53 | @Rule 54 | public RunTestOnContext rule = new RunTestOnContext(); 55 | @Rule 56 | public MockitoRule mockito = MockitoJUnit.rule(); 57 | 58 | @Before 59 | public void setUp(final TestContext context) { 60 | worker = (t, u) -> { 61 | rule.vertx().setTimer(t, event -> { 62 | u.handle(DefaultAsyncResult.succeed()); 63 | }); 64 | }; 65 | queue = new AsyncQueueImpl(worker); 66 | context.assertNotNull(queue); 67 | context.assertEquals(0, queue.getRunning()); 68 | context.assertEquals(5, queue.getConcurrency()); 69 | } 70 | 71 | @Test(timeout = AsyncQueueImplTest.TIMEOUT_LIMIT) 72 | @Repeat(value = AsyncQueueImplTest.REPEAT_LIMIT, silent = true) 73 | public void executeEmptyQueue(final TestContext context) { 74 | context.assertTrue(queue.isIdle()); 75 | rule.vertx().runOnContext(queue); 76 | context.assertEquals(0, queue.getRunning()); 77 | } 78 | 79 | @Test(expected = IllegalArgumentException.class) 80 | public void testNegativeConcurrency() { 81 | queue.setConcurrency(0); 82 | } 83 | 84 | @Test(timeout = AsyncQueueImplTest.TIMEOUT_LIMIT) 85 | @Repeat(value = AsyncQueueImplTest.REPEAT_LIMIT, silent = true) 86 | public void testListeners(final TestContext context) { 87 | final Async async = context.async(); 88 | final AtomicBoolean empty = new AtomicBoolean(false); 89 | final AsyncWorkerListener listener = new AsyncWorkerListener() { 90 | @Override 91 | public void poolEmpty(AsyncWorker instance) { 92 | context.assertNotNull(instance); 93 | empty.set(true); 94 | context.assertTrue(instance.remove(this)); 95 | context.assertFalse(instance.remove(this)); 96 | async.complete(); 97 | } 98 | 99 | @Override 100 | public void poolFull(AsyncWorker instance) { 101 | context.asyncAssertFailure(); 102 | } 103 | }; 104 | context.assertTrue(queue.add(listener)); 105 | context.assertFalse(queue.add(listener)); 106 | queue.add(100, event -> { 107 | context.assertTrue(event.succeeded()); 108 | context.assertTrue(empty.get()); 109 | }, false); 110 | context.assertFalse(queue.isIdle()); 111 | } 112 | 113 | @Test(timeout = AsyncQueueImplTest.TIMEOUT_LIMIT) 114 | @Repeat(value = AsyncQueueImplTest.REPEAT_LIMIT, silent = true) 115 | public void executeOneTaskSucceedInQueue(final TestContext context) { 116 | final Async async = context.async(); 117 | context.assertTrue(queue.add(100, event -> { 118 | context.assertTrue(event.succeeded()); 119 | async.complete(); 120 | }, false)); 121 | context.assertFalse(queue.isIdle()); 122 | } 123 | 124 | @Test(timeout = AsyncQueueImplTest.TIMEOUT_LIMIT) 125 | @Repeat(value = AsyncQueueImplTest.REPEAT_LIMIT, silent = true) 126 | public void executeTwoTaskSucceedWithOneWorker(final TestContext context) { 127 | final Async async = context.async(); 128 | @SuppressWarnings("LocalVariableHidesMemberVariable") 129 | final AsyncQueueImpl queue = new AsyncQueueImpl(worker, 1); 130 | context.assertTrue(queue.add(100, event -> { 131 | context.assertTrue(event.succeeded()); 132 | }, false)); 133 | context.assertTrue(queue.add(200, event -> { 134 | context.assertTrue(event.succeeded()); 135 | async.complete(); 136 | }, false)); 137 | context.assertFalse(queue.isIdle()); 138 | } 139 | 140 | @Test(timeout = AsyncQueueImplTest.TIMEOUT_LIMIT) 141 | @Repeat(value = AsyncQueueImplTest.REPEAT_LIMIT, silent = true) 142 | public void executeTwoTaskSucceedWithDefaultNumberWorkers(final TestContext context) { 143 | final Async async = context.async(); 144 | final AtomicInteger counter = new AtomicInteger(); 145 | context.assertTrue(queue.add(100, event -> { 146 | context.assertTrue(event.succeeded()); 147 | counter.incrementAndGet(); 148 | }, false)); 149 | context.assertTrue(queue.add(200, event -> { 150 | context.assertTrue(event.succeeded()); 151 | async.complete(); 152 | }, false)); 153 | context.assertFalse(queue.isIdle()); 154 | } 155 | 156 | @Test(timeout = AsyncQueueImplTest.TIMEOUT_LIMIT) 157 | @Repeat(value = AsyncQueueImplTest.REPEAT_LIMIT, silent = true) 158 | public void executeOneTaskFailedInQueue(final TestContext context) { 159 | final Async async = context.async(); 160 | queue = new AsyncQueueImpl<>((t, u) -> { 161 | rule.vertx().setTimer(t, event -> { 162 | u.handle(DefaultAsyncResult.fail(new IllegalArgumentException())); 163 | }); 164 | }); 165 | context.assertTrue(queue.add(100, event -> { 166 | context.assertFalse(event.succeeded()); 167 | context.assertTrue(event.cause() instanceof IllegalArgumentException); 168 | async.complete(); 169 | }, false)); 170 | context.assertFalse(queue.isIdle()); 171 | } 172 | 173 | @Test(timeout = AsyncQueueImplTest.TIMEOUT_LIMIT) 174 | @Repeat(value = AsyncQueueImplTest.REPEAT_LIMIT, silent = true) 175 | public void executePauseAndUnpause(final TestContext context) { 176 | final Async async = context.async(); 177 | final AtomicInteger counter = new AtomicInteger(); 178 | queue.setPaused(true); 179 | context.assertTrue(queue.isPaused()); 180 | context.assertTrue(queue.isIdle()); 181 | context.assertTrue(queue.add(100, event -> { 182 | context.assertTrue(event.succeeded()); 183 | counter.incrementAndGet(); 184 | }, false)); 185 | context.assertTrue(queue.add(200, event -> { 186 | context.assertTrue(event.succeeded()); 187 | context.assertFalse(queue.isPaused()); 188 | async.complete(); 189 | }, false)); 190 | context.assertEquals(0, queue.getRunning()); 191 | context.assertFalse(queue.isIdle()); 192 | queue.setPaused(false); 193 | context.assertFalse(queue.isIdle()); 194 | } 195 | 196 | @Test(timeout = AsyncQueueImplTest.TIMEOUT_LIMIT) 197 | @Repeat(value = AsyncQueueImplTest.REPEAT_LIMIT, silent = true) 198 | public void executeAddToTop(final TestContext context) { 199 | final Async async = context.async(); 200 | final AtomicInteger counter = new AtomicInteger(); 201 | queue = new AsyncQueueImpl(worker, 1); 202 | queue.setPaused(true); 203 | context.assertTrue(queue.add(100, event -> { 204 | context.assertTrue(event.succeeded()); 205 | context.assertEquals(2, counter.incrementAndGet()); 206 | async.complete(); 207 | }, false)); 208 | context.assertTrue(queue.add(100, event -> { 209 | context.assertTrue(event.succeeded()); 210 | context.assertFalse(queue.isPaused()); 211 | context.assertEquals(1, counter.incrementAndGet()); 212 | }, true)); 213 | context.assertEquals(0, queue.getRunning()); 214 | context.assertFalse(queue.isIdle()); 215 | queue.setPaused(false); 216 | context.assertFalse(queue.isIdle()); 217 | } 218 | 219 | @Test(timeout = AsyncQueueImplTest.TIMEOUT_LIMIT) 220 | @Repeat(value = AsyncQueueImplTest.REPEAT_LIMIT, silent = true) 221 | public void executeClear(final TestContext context) { 222 | final Async async = context.async(); 223 | final AtomicInteger counter = new AtomicInteger(); 224 | queue.setPaused(true); 225 | context.assertTrue(queue.add(100, event -> { 226 | context.fail(); 227 | }, false)); 228 | context.assertEquals(0, queue.getRunning()); 229 | context.assertFalse(queue.isIdle()); 230 | queue.clear(); 231 | queue.setPaused(false); 232 | context.assertTrue(queue.add(100, event -> { 233 | context.assertTrue(event.succeeded()); 234 | context.assertFalse(queue.isPaused()); 235 | context.assertEquals(1, counter.incrementAndGet()); 236 | async.complete(); 237 | }, false)); 238 | } 239 | 240 | } 241 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/impl/AsyncResultHandlerWrapperTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.ext.unit.junit.VertxUnitRunner; 20 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 21 | import org.junit.Test; 22 | import static org.junit.Assert.*; 23 | import org.junit.Rule; 24 | import org.junit.runner.RunWith; 25 | import org.mockito.junit.MockitoJUnit; 26 | import org.mockito.junit.MockitoRule; 27 | 28 | @RunWith(VertxUnitRunner.class) 29 | public final class AsyncResultHandlerWrapperTest { 30 | 31 | /** 32 | * Timelimit 33 | */ 34 | private static final int LIMIT = 1000; 35 | 36 | @Rule 37 | public MockitoRule mockito = MockitoJUnit.rule(); 38 | 39 | @Test(timeout = AsyncResultHandlerWrapperTest.LIMIT) 40 | public void testWrapperSucceed() { 41 | final AsyncResultHandlerWrapper instance = new AsyncResultHandlerWrapper<>((AsyncResult event) -> { 42 | assertTrue(event.succeeded()); 43 | assertFalse(event.failed()); 44 | assertNull(event.cause()); 45 | assertNull(event.result()); 46 | }); 47 | instance.handle(DefaultAsyncResult.succeed()); 48 | } 49 | 50 | @Test(timeout = AsyncResultHandlerWrapperTest.LIMIT) 51 | public void testWrapperFailed() { 52 | final AsyncResultHandlerWrapper instance = new AsyncResultHandlerWrapper<>((AsyncResult event) -> { 53 | assertFalse(event.succeeded()); 54 | assertTrue(event.failed()); 55 | assertTrue(event.cause() instanceof UnsupportedOperationException); 56 | assertNull(event.result()); 57 | }); 58 | instance.handle(DefaultAsyncResult.fail(new UnsupportedOperationException())); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/impl/AsyncUtilsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 19 | import io.vertx.core.AsyncResult; 20 | import io.vertx.core.Handler; 21 | import io.vertx.ext.unit.Async; 22 | import io.vertx.ext.unit.TestContext; 23 | import io.vertx.ext.unit.junit.Repeat; 24 | import io.vertx.ext.unit.junit.RepeatRule; 25 | import io.vertx.ext.unit.junit.RunTestOnContext; 26 | import io.vertx.ext.unit.junit.VertxUnitRunner; 27 | import io.zatarox.vertx.async.api.AsyncUtils; 28 | import io.zatarox.vertx.async.api.BiHandler; 29 | import java.util.concurrent.TimeUnit; 30 | import java.util.concurrent.TimeoutException; 31 | import java.util.concurrent.atomic.AtomicInteger; 32 | import org.junit.Before; 33 | import org.junit.Rule; 34 | import org.junit.Test; 35 | import org.junit.runner.RunWith; 36 | import org.mockito.junit.MockitoJUnit; 37 | import org.mockito.junit.MockitoRule; 38 | 39 | @RunWith(VertxUnitRunner.class) 40 | public final class AsyncUtilsTest { 41 | 42 | /** 43 | * Limits 44 | */ 45 | private static final int TIMEOUT_LIMIT = 1500; 46 | private static final int REPEAT_LIMIT = 100; 47 | 48 | @Rule 49 | public RepeatRule repeater = new RepeatRule(); 50 | @Rule 51 | public RunTestOnContext rule = new RunTestOnContext(); 52 | @Rule 53 | public MockitoRule mockito = MockitoJUnit.rule(); 54 | private AsyncUtils instance; 55 | 56 | @Before 57 | public void setUp(final TestContext context) { 58 | instance = new AsyncUtilsImpl(rule.vertx().getOrCreateContext()); 59 | } 60 | 61 | @Test(timeout = AsyncUtilsTest.TIMEOUT_LIMIT) 62 | @Repeat(value = AsyncUtilsTest.REPEAT_LIMIT, silent = true) 63 | public void timeoutNotRaised(final TestContext context) { 64 | final AtomicInteger handlerCallCount = new AtomicInteger(0); 65 | final Async async = context.async(); 66 | instance.timeout(handler -> { 67 | handler.handle(DefaultAsyncResult.succeed()); 68 | }, TimeUnit.MILLISECONDS, 100L, result -> { 69 | context.assertNotNull(result); 70 | context.assertTrue(result.succeeded()); 71 | context.assertNull(result.result()); 72 | context.assertEquals(1, handlerCallCount.incrementAndGet()); 73 | async.complete(); 74 | }); 75 | } 76 | 77 | @Test(timeout = AsyncUtilsTest.TIMEOUT_LIMIT) 78 | @Repeat(value = AsyncUtilsTest.REPEAT_LIMIT, silent = true) 79 | public void timeoutNotRaisedWithError(final TestContext context) { 80 | final AtomicInteger handlerCallCount = new AtomicInteger(0); 81 | final Async async = context.async(); 82 | instance.timeout(handler -> { 83 | handler.handle(DefaultAsyncResult.fail(new IllegalArgumentException())); 84 | }, TimeUnit.MILLISECONDS, 100L, result -> { 85 | context.assertNotNull(result); 86 | context.assertFalse(result.succeeded()); 87 | context.assertNull(result.result()); 88 | context.assertTrue(result.cause() instanceof IllegalArgumentException); 89 | context.assertEquals(1, handlerCallCount.incrementAndGet()); 90 | async.complete(); 91 | }); 92 | } 93 | 94 | @Test(timeout = AsyncUtilsTest.TIMEOUT_LIMIT) 95 | @Repeat(value = AsyncUtilsTest.REPEAT_LIMIT, silent = true) 96 | public void timeoutRaised(final TestContext context) { 97 | final AtomicInteger handlerCallCount = new AtomicInteger(0); 98 | final Async async = context.async(); 99 | instance.timeout(handler -> { 100 | rule.vertx().setTimer(1000, id -> { 101 | handler.handle(DefaultAsyncResult.succeed()); 102 | }); 103 | }, TimeUnit.MILLISECONDS, 100L, result -> { 104 | context.assertNotNull(result); 105 | context.assertFalse(result.succeeded()); 106 | context.assertNull(result.result()); 107 | context.assertTrue(result.cause() instanceof TimeoutException); 108 | context.assertEquals(1, handlerCallCount.incrementAndGet()); 109 | async.complete(); 110 | }); 111 | } 112 | 113 | @Test(timeout = AsyncUtilsTest.TIMEOUT_LIMIT) 114 | @Repeat(value = AsyncUtilsTest.REPEAT_LIMIT, silent = true) 115 | public void timeoutRaisedWithError(final TestContext context) { 116 | final AtomicInteger handlerCallCount = new AtomicInteger(0); 117 | final Async async = context.async(); 118 | instance.timeout(handler -> { 119 | rule.vertx().setTimer(1000, id -> { 120 | handler.handle(DefaultAsyncResult.fail(new IllegalArgumentException())); 121 | }); 122 | }, TimeUnit.MILLISECONDS, 100L, result -> { 123 | context.assertNotNull(result); 124 | context.assertFalse(result.succeeded()); 125 | context.assertNull(result.result()); 126 | context.assertTrue(result.cause() instanceof TimeoutException); 127 | context.assertEquals(1, handlerCallCount.incrementAndGet()); 128 | async.complete(); 129 | }); 130 | } 131 | 132 | @Test(timeout = AsyncUtilsTest.TIMEOUT_LIMIT) 133 | public void createMemoize(final TestContext context) { 134 | instance.memoize((item, handler) -> { 135 | handler.handle(DefaultAsyncResult.succeed(item)); 136 | }); 137 | } 138 | 139 | @Test(timeout = AsyncUtilsTest.TIMEOUT_LIMIT) 140 | @Repeat(value = AsyncUtilsTest.REPEAT_LIMIT, silent = true) 141 | public void constantWithNull(final TestContext context) { 142 | final Long value = (long) 73; 143 | final Handler>> function = instance.constant(value); 144 | final Async async = context.async(); 145 | context.assertNotNull(function); 146 | rule.vertx().runOnContext(event -> { 147 | function.handle(event1 -> { 148 | context.assertTrue(event1.succeeded()); 149 | context.assertEquals(value, event1.result()); 150 | async.complete(); 151 | }); 152 | }); 153 | } 154 | 155 | @Test(timeout = AsyncUtilsTest.TIMEOUT_LIMIT) 156 | @Repeat(value = AsyncUtilsTest.REPEAT_LIMIT, silent = true) 157 | public void asyncifyAFunction(final TestContext context) { 158 | final Async async = context.async(); 159 | final BiHandler>> function = instance.asyncify(t -> { 160 | return t + 1; 161 | }); 162 | context.assertNotNull(function); 163 | rule.vertx().runOnContext(handler -> { 164 | function.handle(72, result -> { 165 | context.assertTrue(result.succeeded()); 166 | context.assertEquals(73, result.result()); 167 | async.complete(); 168 | }); 169 | }); 170 | } 171 | 172 | @Test(timeout = AsyncUtilsTest.TIMEOUT_LIMIT) 173 | @Repeat(value = AsyncUtilsTest.REPEAT_LIMIT, silent = true) 174 | public void asyncifyAFunctionUnhandledException(final TestContext context) { 175 | final Async async = context.async(); 176 | final BiHandler>> function = instance.asyncify(t -> { 177 | throw new RuntimeException(); 178 | }); 179 | context.assertNotNull(function); 180 | rule.vertx().runOnContext(handler -> { 181 | function.handle(72, result -> { 182 | context.assertFalse(result.succeeded()); 183 | context.assertTrue(result.cause() instanceof RuntimeException); 184 | async.complete(); 185 | }); 186 | }); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/impl/LoopRetryOptionsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.impl; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.core.Handler; 20 | import io.vertx.ext.unit.Async; 21 | import io.vertx.ext.unit.TestContext; 22 | import io.vertx.ext.unit.junit.Repeat; 23 | import io.vertx.ext.unit.junit.RepeatRule; 24 | import io.vertx.ext.unit.junit.RunTestOnContext; 25 | import io.vertx.ext.unit.junit.VertxUnitRunner; 26 | import io.zatarox.vertx.async.AsyncFactorySingleton; 27 | import io.zatarox.vertx.async.utils.DefaultAsyncResult; 28 | import java.util.concurrent.atomic.AtomicInteger; 29 | import org.junit.Test; 30 | import static org.junit.Assert.*; 31 | import org.junit.Before; 32 | import org.junit.Rule; 33 | import org.junit.runner.RunWith; 34 | import static org.mockito.Mockito.*; 35 | import org.mockito.junit.MockitoJUnit; 36 | import org.mockito.junit.MockitoRule; 37 | 38 | @RunWith(VertxUnitRunner.class) 39 | public final class LoopRetryOptionsTest { 40 | 41 | /** 42 | * Limits 43 | */ 44 | private static final int TIMEOUT_LIMIT = 1000; 45 | private static final int REPEAT_LIMIT = 100; 46 | 47 | private LoopRetryOptions options; 48 | 49 | @Rule 50 | public RepeatRule repeater = new RepeatRule(); 51 | @Rule 52 | public RunTestOnContext rule = new RunTestOnContext(); 53 | @Rule 54 | public MockitoRule mockito = MockitoJUnit.rule(); 55 | 56 | @Before 57 | public void setUp() { 58 | options = new LoopRetryOptions(10); 59 | assertEquals(10, options.getTries()); 60 | } 61 | 62 | @Test(expected = IllegalArgumentException.class) 63 | public void negativeTry() { 64 | assertNull(new LoopRetryOptions(-1)); 65 | } 66 | 67 | @Test(timeout = LoopRetryOptionsTest.TIMEOUT_LIMIT) 68 | @Repeat(value = LoopRetryOptionsTest.REPEAT_LIMIT, silent = true) 69 | public void retryExecutesTheTaskWithoutError(final TestContext context) { 70 | final Handler>> task = mock(Handler.class); 71 | final Async async = context.async(); 72 | 73 | doAnswer(invocation -> { 74 | final Handler> handler = invocation.getArgumentAt(0, Handler.class); 75 | handler.handle(DefaultAsyncResult.succeed("TEST")); 76 | return null; 77 | }).when(task).handle(any(Handler.class)); 78 | 79 | AsyncFactorySingleton.getInstance().createFlows(rule.vertx().getOrCreateContext()).retry(options, task, result -> { 80 | verify(task, times(1)).handle(any(Handler.class)); 81 | context.assertNotNull(result); 82 | context.assertTrue(result.succeeded()); 83 | context.assertEquals("TEST", result.result()); 84 | async.complete(); 85 | }); 86 | } 87 | 88 | @Test(timeout = LoopRetryOptionsTest.TIMEOUT_LIMIT) 89 | @Repeat(value = LoopRetryOptionsTest.REPEAT_LIMIT, silent = true) 90 | public void retryExecutesAndFaildOnAllIteratee(final TestContext context) { 91 | final Handler>> task = mock(Handler.class); 92 | final Async async = context.async(); 93 | 94 | doAnswer(invocation -> { 95 | final Handler> handler = invocation.getArgumentAt(0, Handler.class); 96 | handler.handle(DefaultAsyncResult.fail(new RuntimeException("Failed"))); 97 | return null; 98 | }).when(task).handle(any(Handler.class)); 99 | 100 | AsyncFactorySingleton.getInstance().createFlows(rule.vertx().getOrCreateContext()).retry(options, task, result -> { 101 | verify(task, times(10)).handle(any(Handler.class)); 102 | context.assertNotNull(result); 103 | context.assertFalse(result.succeeded()); 104 | context.assertNull(result.result()); 105 | async.complete(); 106 | }); 107 | } 108 | 109 | @Test(timeout = LoopRetryOptionsTest.TIMEOUT_LIMIT) 110 | @Repeat(value = LoopRetryOptionsTest.REPEAT_LIMIT, silent = true) 111 | public void retryExecutesSuccessBeforeLastFailure(final TestContext context) { 112 | final Handler>> task = mock(Handler.class); 113 | final AtomicInteger counter = new AtomicInteger(0); 114 | final Async async = context.async(); 115 | 116 | doAnswer(invocation -> { 117 | final Handler> handler = invocation.getArgumentAt(0, Handler.class); 118 | if (counter.incrementAndGet() < 10) { 119 | handler.handle(DefaultAsyncResult.fail(new RuntimeException("Failed"))); 120 | } else { 121 | handler.handle(DefaultAsyncResult.succeed("TASK 1")); 122 | } 123 | return null; 124 | }).when(task).handle(any(Handler.class)); 125 | 126 | AsyncFactorySingleton.getInstance().createFlows(rule.vertx().getOrCreateContext()).retry(options, task, result -> { 127 | verify(task, times(10)).handle(any(Handler.class)); 128 | context.assertNotNull(result); 129 | context.assertTrue(result.succeeded()); 130 | context.assertEquals("TASK 1", result.result()); 131 | async.complete(); 132 | }); 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/test/java/unit/io/zatarox/vertx/async/utils/DefaultAsyncResultTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2016 Guillaume Chauvet. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.zatarox.vertx.async.utils; 17 | 18 | import io.vertx.core.AsyncResult; 19 | import io.vertx.ext.unit.Async; 20 | import io.vertx.ext.unit.TestContext; 21 | import io.vertx.ext.unit.junit.Repeat; 22 | import io.vertx.ext.unit.junit.RepeatRule; 23 | import io.vertx.ext.unit.junit.RunTestOnContext; 24 | import io.vertx.ext.unit.junit.VertxUnitRunner; 25 | import org.junit.Rule; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.mockito.junit.MockitoJUnit; 29 | import org.mockito.junit.MockitoRule; 30 | 31 | @RunWith(VertxUnitRunner.class) 32 | public final class DefaultAsyncResultTest { 33 | 34 | /** 35 | * Limits 36 | */ 37 | private static final int TIMEOUT_LIMIT = 1000; 38 | private static final int REPEAT_LIMIT = 100; 39 | 40 | @Rule 41 | public RepeatRule repeater = new RepeatRule(); 42 | @Rule 43 | public RunTestOnContext rule = new RunTestOnContext(); 44 | @Rule 45 | public MockitoRule mockito = MockitoJUnit.rule(); 46 | 47 | @Test(timeout = DefaultAsyncResultTest.TIMEOUT_LIMIT) 48 | @Repeat(value = DefaultAsyncResultTest.REPEAT_LIMIT, silent = true) 49 | public void validFailedException(final TestContext context) { 50 | final Async async = context.async(); 51 | final AsyncResult instance = DefaultAsyncResult.fail(new UnsupportedOperationException()); 52 | rule.vertx().runOnContext(event -> { 53 | context.assertFalse(instance.succeeded()); 54 | context.assertTrue(instance.failed()); 55 | context.assertTrue(instance.cause() instanceof UnsupportedOperationException); 56 | async.complete(); 57 | }); 58 | } 59 | 60 | @Test(timeout = DefaultAsyncResultTest.TIMEOUT_LIMIT) 61 | @Repeat(value = DefaultAsyncResultTest.REPEAT_LIMIT, silent = true) 62 | public void validFaileAsyncResult(final TestContext context) { 63 | final Async async = context.async(); 64 | final AsyncResult instance = DefaultAsyncResult.fail(DefaultAsyncResult.fail(new UnsupportedOperationException())); 65 | rule.vertx().runOnContext(event -> { 66 | context.assertFalse(instance.succeeded()); 67 | context.assertTrue(instance.failed()); 68 | context.assertTrue(instance.cause() instanceof UnsupportedOperationException); 69 | async.complete(); 70 | }); 71 | } 72 | 73 | @Test(timeout = DefaultAsyncResultTest.TIMEOUT_LIMIT, expected = IllegalArgumentException.class) 74 | @Repeat(value = DefaultAsyncResultTest.REPEAT_LIMIT, silent = true) 75 | public void unvalidFailed(final TestContext context) { 76 | final Async async = context.async(); 77 | final AsyncResult instance = DefaultAsyncResult.fail((Throwable) null); 78 | rule.vertx().runOnContext(event -> { 79 | context.assertNull(instance); 80 | context.fail(); 81 | async.complete(); 82 | }); 83 | } 84 | 85 | @Test(timeout = DefaultAsyncResultTest.TIMEOUT_LIMIT) 86 | @Repeat(value = DefaultAsyncResultTest.REPEAT_LIMIT, silent = true) 87 | public void validVoidSuccess(final TestContext context) { 88 | final Async async = context.async(); 89 | final AsyncResult instance = DefaultAsyncResult.succeed(); 90 | rule.vertx().runOnContext(event -> { 91 | context.assertTrue(instance.succeeded()); 92 | context.assertFalse(instance.failed()); 93 | context.assertNull(instance.cause()); 94 | context.assertNull(instance.result()); 95 | async.complete(); 96 | }); 97 | } 98 | 99 | @Test(timeout = DefaultAsyncResultTest.TIMEOUT_LIMIT) 100 | @Repeat(value = DefaultAsyncResultTest.REPEAT_LIMIT, silent = true) 101 | public void validValueSuccess(final TestContext context) { 102 | final Async async = context.async(); 103 | final AsyncResult instance = DefaultAsyncResult.succeed(73); 104 | rule.vertx().runOnContext(event -> { 105 | context.assertTrue(instance.succeeded()); 106 | context.assertFalse(instance.failed()); 107 | context.assertNull(instance.cause()); 108 | context.assertEquals(73, instance.result()); 109 | async.complete(); 110 | }); 111 | } 112 | } 113 | --------------------------------------------------------------------------------