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 java.util.Optional;
023import java.util.concurrent.CancellationException;
024import java.util.concurrent.CompletableFuture;
025import java.util.concurrent.CompletionStage;
026import java.util.concurrent.ExecutionException;
027import java.util.concurrent.TimeUnit;
028import java.util.function.Consumer;
029import java.util.function.Function;
030
031/**
032 * Last Step of the builder of {@link CompletableFuture} to create the
033 * completable operation it self.
034 * 
035 * @param <T>
036 *            The type of result of the {@link CompletableFuture}
037 * @since 1.0.0
038 */
039public interface WaitResultBuilder6<T> {
040
041        /**
042         * Create and start the async execution of the {@link CompletableFuture} the
043         * executor that was defined before.
044         * <p>
045         * This method is the <i>main</i> method of this interface. This start the
046         * execution of the {@link CompletableFuture} based on the parameter defined
047         * before.
048         * <p>
049         * For example:
050         * 
051         * <pre>
052         * CompletableFuture&lt;Optional&lt;String&gt;&gt; future = WaitResult.of(myCallable).dontIgnoreException()
053         *              .expecting(myPredicate).repeat(2).every(1000, TimeUnit.MILLISECONDS).usingDefaultExecutor().asyncExec();
054         * </pre>
055         * 
056         * This defines a {@link CompletableFuture} that will repeat maximum two time,
057         * with a wait time of 1000ms, the execution of {@code myCallable}, doesn't
058         * ignore the exception, verify the {@code myPredicate} condition. This
059         * {@link CompletableFuture} will use the default executor.
060         * 
061         * @return the {@link CompletableFuture}
062         */
063        CompletableFuture<Optional<T>> asyncExec();
064
065        /**
066         * Directly wait for the result of this execution. In case of not ignored
067         * exception, an {@link AssertionError} is thrown.
068         * <p>
069         * This method is a <i>shortcut</i> method to {@code asyncExec().get()}, which
070         * throw AssertionError in case of error.
071         * 
072         * @return the {@link Optional} with the result of the execution
073         * 
074         * @throws AssertionError
075         *             In case of not ignored exception.
076         * @see #asyncExec()
077         * @see CompletableFuture#get()
078         */
079        default Optional<T> finish() {
080                try {
081                        return asyncExec().get();
082                } catch (InterruptedException | ExecutionException e) {
083                        throw Optional.ofNullable(e.getCause()).filter(c -> c instanceof AssertionError)
084                                        .map(AssertionError.class::cast)
085                                        .orElseGet(() -> new AssertionError("Unexpected error " + e.getMessage(), e));
086                }
087        }
088
089        /**
090         * Directly wait for a positive result of this execution. In case of not ignored
091         * exception, or when no result are available, an {@link AssertionError} is
092         * thrown.
093         * <p>
094         * This method is a <i>shortcut</i> method to the finish method that read the
095         * optional value and throw an AssertionError in case of mission value.
096         * 
097         * @return the value if available
098         * 
099         * @throws AssertionError
100         *             In case of not ignored exception or missing result.
101         * @see #finish()
102         */
103        default T finishWithAResult() {
104                return finish().orElseThrow(() -> new AssertionError("No result is available"));
105        }
106
107        /**
108         * Shortcut method to the join of the {@link CompletableFuture}.
109         * <p>
110         * Only runtime exception in case of error.
111         * 
112         * @return the result of the wait
113         * @since 1.0.0
114         * @see CompletableFuture#join()
115         * @see #asyncExec()
116         */
117        default Optional<T> join() {
118                return asyncExec().join();
119        }
120
121        /**
122         * Shortcut method to the join of the {@link CompletableFuture}, that expect a
123         * positive result.
124         * <p>
125         * Only runtime exception in case of error.
126         * 
127         * @return the result of the wait
128         * @since 1.0.0
129         * @see CompletableFuture#join()
130         * @see #join()
131         */
132        default T joinWithAResult() {
133                return join().orElseThrow(() -> new AssertionError("No result is available when one is expected"));
134        }
135
136        /**
137         * Create and start the async execution of the {@link CompletableFuture} and
138         * directly register a Consumer on the result.
139         * 
140         * @param action
141         *            the action to be done on the result
142         * @return the {@link CompletableFuture}
143         * @since 1.0.0
144         * @see CompletableFuture#thenAccept(Consumer)
145         * @see #asyncExec()
146         */
147        default CompletableFuture<Void> thenAccept(Consumer<? super Optional<T>> action) {
148                return asyncExec().thenAccept(action);
149        }
150
151        /**
152         * Create and start the async execution of the {@link CompletableFuture} and
153         * directly register a Function on the result.
154         * 
155         * @param fn
156         *            then function to be applied
157         * 
158         * @param <U>
159         *            The new return type
160         * @return the {@link CompletableFuture}
161         * @since 1.0.0
162         * @see CompletableFuture#thenApply(Function)
163         * @see #asyncExec()
164         */
165        default <U> CompletableFuture<U> thenApply(Function<? super Optional<T>, ? extends U> fn) {
166                return asyncExec().thenApply(fn);
167        }
168
169        /**
170         * Create and start the async execution of the {@link CompletableFuture} and
171         * exceptionally completes this CompletableFuture with a TimeoutException if not
172         * otherwise completed before the given timeout.
173         * <p>
174         * <b>Only available on java 9</b>
175         * 
176         * @param timeout
177         *            how long to wait before completing exceptionally with a
178         *            TimeoutException, in units of unit
179         * @param unit
180         *            a TimeUnit determining how to interpret the timeout parameter
181         * @return the {@link CompletableFuture}
182         * @since 1.0.0
183         * @see CompletableFuture#orTimeout(long, TimeUnit)
184         * @see #asyncExec()
185         */
186        default CompletableFuture<Optional<T>> orTimeout(long timeout, TimeUnit unit) {
187                throw new UnsupportedOperationException("Not available on java 8");
188        }
189
190        /**
191         * Returns a new CompletionStage that is completed normally based on this
192         * {@link CompletableFuture}.
193         * <p>
194         * <b>Only available on java 9</b>
195         *
196         * @return the new CompletionStage
197         * @since 1.0.0
198         * @see CompletableFuture#minimalCompletionStage()
199         * @see #asyncExec()
200         */
201        default CompletionStage<Optional<T>> minimalCompletionStage​() {
202                throw new UnsupportedOperationException("Not available on java 8");
203        }
204
205        /**
206         * Waits if necessary for the produced future to complete, and then returns its
207         * result.
208         *
209         * @return the result value
210         * @throws CancellationException
211         *             if the produced future was cancelled
212         * @throws ExecutionException
213         *             if the produced future completed exceptionally
214         * @throws InterruptedException
215         *             if the current thread was interrupted while waiting
216         * @see CompletableFuture#get()
217         * @see #asyncExec()
218         * @since 1.0.0
219         */
220        default Optional<T> get() throws InterruptedException, ExecutionException {
221                return asyncExec().get();
222        }
223}