001/**
002 * Powerunit - A JDK1.8 test framework
003 * Copyright (C) 2014 Mathieu Boretti.
004 *
005 * This file is part of Powerunit
006 *
007 * Powerunit is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation, either version 3 of the License, or
010 * (at your option) any later version.
011 *
012 * Powerunit is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>.
019 */
020package ch.powerunit.extensions.async.lang;
021
022import static java.util.concurrent.CompletableFuture.supplyAsync;
023import static java.util.concurrent.ForkJoinPool.commonPool;
024
025import java.util.Optional;
026import java.util.concurrent.CompletableFuture;
027import java.util.concurrent.Executor;
028import java.util.concurrent.ForkJoinPool;
029import java.util.function.Function;
030import java.util.function.Predicate;
031import java.util.function.Supplier;
032
033/**
034 * Almost final Step of the builder of {@link CompletableFuture} to define the
035 * executor it self.
036 * 
037 * @param <T>
038 *            The type of result of the {@link CompletableFuture}
039 *
040 */
041public interface WaitResultBuilder5<T> extends Supplier<Optional<T>> {
042
043        /**
044         * Directly wait for the result of this execution (the execution is run in this
045         * thread). In case of not ignored exception, an {@link AssertionError} is
046         * thrown.
047         * <p>
048         * 
049         * For example :
050         * 
051         * <pre>
052         * WaitResult.of(myCallable).dontIgnoreException().expecting(myPredicate).repeat(2)
053         *              .every(1000, TimeUnit.MILLISECONDS).get()
054         * </pre>
055         * <ul>
056         * <li>If an exception occurs in {@code myCallable}, an {@link AssertionError}
057         * is thrown</li>
058         * <li>If no result is available, after the 2 try, an empty {@link Optional} is
059         * returned.</li>
060         * <li>Or the result is available in the returned {@link Optional}.</li>
061         * </ul>
062         * 
063         * @return the {@link Optional} with the result of the execution
064         * 
065         * @throws AssertionError
066         *             In case of not ignored exception.
067         */
068        @Override
069        Optional<T> get();
070
071        /**
072         * Register an action to be done when the retrieval is finish (in success or
073         * not).
074         * <p>
075         * This may be used, for example, to release resources. This method may be used
076         * several times. In this case, all the registered action will be executed on
077         * Finish, starting by the first one.
078         * 
079         * @param action
080         *            the action to be done. May be null (ignored).
081         * @return a new instance of {@link WaitResultBuilder5} with this new action to
082         *         be done at the end.
083         * @since 1.1.0
084         */
085        default WaitResultBuilder5<T> onFinish(Runnable action) {
086                if (action == null) {
087                        return this;
088                }
089                return () -> {
090                        try {
091                                return get();
092                        } finally {
093                                action.run();
094                        }
095                };
096        }
097
098        /**
099         * Define the executor to be used for the async part.
100         * <p>
101         * Both the action to retry and the control on the result will be executed on
102         * the thread provided by the executor.
103         * 
104         * @param executor
105         *            the executor to be used. This can't be null.
106         * @return {@link WaitResultBuilder6 the final step}
107         */
108        default WaitResultBuilder6<T> using(Executor executor) {
109                return () -> supplyAsync(this, executor);
110        }
111
112        /**
113         * Define the executor to be used for the async part as using
114         * {@link ForkJoinPool#commonPool()}.
115         * <p>
116         * Both the action to retry and the control on the result will be executed on
117         * the thread provided by the executor.
118         * 
119         * @return {@link WaitResultBuilder6 the final step}
120         * @see ForkJoinPool#commonPool()
121         */
122        default WaitResultBuilder6<T> usingDefaultExecutor() {
123                return using(commonPool());
124        }
125
126        /**
127         * Create and start the async execution of the {@link CompletableFuture}.
128         * 
129         * @param executor
130         *            the executor to be used.
131         * @return the {@link CompletableFuture}
132         * @deprecated Replaced by {@code using(executor).asyncExec()}
133         */
134        @Deprecated
135        default CompletableFuture<Optional<T>> asyncExec(Executor executor) {
136                return using(executor).asyncExec();
137        }
138
139        /**
140         * Create and start the async execution of the {@link CompletableFuture} using
141         * {@link ForkJoinPool#commonPool()}.
142         * 
143         * @return the {@link CompletableFuture}
144         * @see #usingDefaultExecutor()
145         * @see WaitResultBuilder6#asyncExec()
146         */
147        default CompletableFuture<Optional<T>> asyncExec() {
148                return usingDefaultExecutor().asyncExec();
149        }
150
151        /**
152         * Directly wait for the result of this execution. In case of not ignored
153         * exception, an {@link AssertionError} is thrown.
154         * 
155         * @param executor
156         *            the executor to be used.
157         * 
158         * @return the {@link Optional} with the result of the execution
159         * 
160         * @throws AssertionError
161         *             In case of not ignored exception.
162         * @deprecated Replaced by {@code using(executor).finish()}
163         */
164        @Deprecated
165        default Optional<T> finish(Executor executor) {
166                return using(executor).finish();
167        }
168
169        /**
170         * Directly wait for the result of this execution using
171         * {@link ForkJoinPool#commonPool()}. In case of not ignored exception, an
172         * {@link AssertionError} is thrown.
173         * 
174         * @return the {@link Optional} with the result of the execution
175         * 
176         * @throws AssertionError
177         *             In case of not ignored exception.
178         * @see #usingDefaultExecutor()
179         * @see WaitResultBuilder6#finish()
180         */
181        default Optional<T> finish() {
182                return usingDefaultExecutor().finish();
183        }
184
185        /**
186         * Directly wait for a positive result of this execution. In case of not ignored
187         * exception, or when no result are available, an {@link AssertionError} is
188         * thrown.
189         * 
190         * @param executor
191         *            the executor to be used.
192         * 
193         * @return the value if available
194         * 
195         * @throws AssertionError
196         *             In case of not ignored exception or missing result.
197         * @deprecated Replaced by {@code using(executor).finishWithAResult()}
198         */
199        @Deprecated
200        default T finishWithAResult(Executor executor) {
201                return using(executor).finishWithAResult();
202        }
203
204        /**
205         * Directly wait for a positive result of this execution using
206         * {@link ForkJoinPool#commonPool()}. In case of not ignored exception, or when
207         * no result are available, an {@link AssertionError} is thrown.
208         * 
209         * @return the value if available
210         * 
211         * @throws AssertionError
212         *             In case of not ignored exception or missing result.
213         * @see #usingDefaultExecutor()
214         * @see WaitResultBuilder6#finishWithAResult()
215         */
216        default T finishWithAResult() {
217                return usingDefaultExecutor().finishWithAResult();
218        }
219
220        /**
221         * Add a mapper fonction, on the result, if applicable. This mapper is executed
222         * in the target thread.
223         * 
224         * @param mapper
225         *            the function to convert the result.
226         * @param <U>
227         *            the target of the mapper.
228         * @return the {@link WaitResultBuilder5} continuation of the builder
229         * @see Optional#map(Function)
230         * @since 1.0.0
231         */
232        default <U> WaitResultBuilder5<U> map(Function<T, U> mapper) {
233                return () -> get().map(mapper);
234        }
235
236        /**
237         * Add a flat mapper fonction, on the result, if applicable. This mapper is
238         * executed in the target thread.
239         * 
240         * @param mapper
241         *            the function to convert the result.
242         * @param <U>
243         *            the target of the mapper.
244         * @return the {@link WaitResultBuilder5} continuation of the builder
245         * @see Optional#flatMap(Function)
246         * @since 1.1.0
247         */
248        default <U> WaitResultBuilder5<U> flatMap(Function<T, Optional<U>> mapper) {
249                return () -> get().flatMap(mapper);
250        }
251
252        /**
253         * Add a or operation, on the result, if applicable. This or is executed in the
254         * target thread.
255         * <p>
256         * <b>Only available on java 9</b>
257         * 
258         * @param supplier
259         *            the function to convert the result
260         * @return the {@link WaitResultBuilder5} continuation of the builder
261         * @see Optional#or(Supplier)
262         * @since 1.1.0
263         */
264        default WaitResultBuilder5<T> or(Supplier<? extends Optional<? extends T>> supplier) {
265                throw new UnsupportedOperationException("Not available on java 8");
266        }
267
268        /**
269         * Add a filter predicate, on the result, if applicable. This filter is executed
270         * in the target thread.
271         * 
272         * @param filter
273         *            the filter
274         * @return the {@link WaitResultBuilder5} continuation of the builder
275         * @see Optional#filter(Predicate)
276         * @since 1.0.0
277         */
278        default WaitResultBuilder5<T> filter(Predicate<T> filter) {
279                return () -> get().filter(filter);
280        }
281}