WaitResultBuilder6.java
/**
* Powerunit - A JDK1.8 test framework
* Copyright (C) 2014 Mathieu Boretti.
*
* This file is part of Powerunit
*
* Powerunit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Powerunit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Powerunit. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.powerunit.extensions.async.lang;
import java.util.Optional;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Last Step of the builder of {@link CompletableFuture} to create the
* completable operation it self.
*
* @param <T>
* The type of result of the {@link CompletableFuture}
* @since 1.0.0
*/
public interface WaitResultBuilder6<T> {
/**
* Create and start the async execution of the {@link CompletableFuture} the
* executor that was defined before.
* <p>
* This method is the <i>main</i> method of this interface. This start the
* execution of the {@link CompletableFuture} based on the parameter defined
* before.
* <p>
* For example:
*
* <pre>
* CompletableFuture<Optional<String>> future = WaitResult.of(myCallable).dontIgnoreException()
* .expecting(myPredicate).repeat(2).every(1000, TimeUnit.MILLISECONDS).usingDefaultExecutor().asyncExec();
* </pre>
*
* This defines a {@link CompletableFuture} that will repeat maximum two time,
* with a wait time of 1000ms, the execution of {@code myCallable}, doesn't
* ignore the exception, verify the {@code myPredicate} condition. This
* {@link CompletableFuture} will use the default executor.
*
* @return the {@link CompletableFuture}
*/
CompletableFuture<Optional<T>> asyncExec();
/**
* Directly wait for the result of this execution. In case of not ignored
* exception, an {@link AssertionError} is thrown.
* <p>
* This method is a <i>shortcut</i> method to {@code asyncExec().get()}, which
* throw AssertionError in case of error.
*
* @return the {@link Optional} with the result of the execution
*
* @throws AssertionError
* In case of not ignored exception.
* @see #asyncExec()
* @see CompletableFuture#get()
*/
default Optional<T> finish() {
try {
return asyncExec().get();
} catch (InterruptedException | ExecutionException e) {
throw Optional.ofNullable(e.getCause()).filter(c -> c instanceof AssertionError)
.map(AssertionError.class::cast)
.orElseGet(() -> new AssertionError("Unexpected error " + e.getMessage(), e));
}
}
/**
* Directly wait for a positive result of this execution. In case of not ignored
* exception, or when no result are available, an {@link AssertionError} is
* thrown.
* <p>
* This method is a <i>shortcut</i> method to the finish method that read the
* optional value and throw an AssertionError in case of mission value.
*
* @return the value if available
*
* @throws AssertionError
* In case of not ignored exception or missing result.
* @see #finish()
*/
default T finishWithAResult() {
return finish().orElseThrow(() -> new AssertionError("No result is available"));
}
/**
* Shortcut method to the join of the {@link CompletableFuture}.
* <p>
* Only runtime exception in case of error.
*
* @return the result of the wait
* @since 1.0.0
* @see CompletableFuture#join()
* @see #asyncExec()
*/
default Optional<T> join() {
return asyncExec().join();
}
/**
* Shortcut method to the join of the {@link CompletableFuture}, that expect a
* positive result.
* <p>
* Only runtime exception in case of error.
*
* @return the result of the wait
* @since 1.0.0
* @see CompletableFuture#join()
* @see #join()
*/
default T joinWithAResult() {
return join().orElseThrow(() -> new AssertionError("No result is available when one is expected"));
}
/**
* Create and start the async execution of the {@link CompletableFuture} and
* directly register a Consumer on the result.
*
* @param action
* the action to be done on the result
* @return the {@link CompletableFuture}
* @since 1.0.0
* @see CompletableFuture#thenAccept(Consumer)
* @see #asyncExec()
*/
default CompletableFuture<Void> thenAccept(Consumer<? super Optional<T>> action) {
return asyncExec().thenAccept(action);
}
/**
* Create and start the async execution of the {@link CompletableFuture} and
* directly register a Function on the result.
*
* @param fn
* then function to be applied
*
* @param <U>
* The new return type
* @return the {@link CompletableFuture}
* @since 1.0.0
* @see CompletableFuture#thenApply(Function)
* @see #asyncExec()
*/
default <U> CompletableFuture<U> thenApply(Function<? super Optional<T>, ? extends U> fn) {
return asyncExec().thenApply(fn);
}
/**
* Create and start the async execution of the {@link CompletableFuture} and
* exceptionally completes this CompletableFuture with a TimeoutException if not
* otherwise completed before the given timeout.
* <p>
* <b>Only available on java 9</b>
*
* @param timeout
* how long to wait before completing exceptionally with a
* TimeoutException, in units of unit
* @param unit
* a TimeUnit determining how to interpret the timeout parameter
* @return the {@link CompletableFuture}
* @since 1.0.0
* @see CompletableFuture#orTimeout(long, TimeUnit)
* @see #asyncExec()
*/
default CompletableFuture<Optional<T>> orTimeout(long timeout, TimeUnit unit) {
throw new UnsupportedOperationException("Not available on java 8");
}
/**
* Returns a new CompletionStage that is completed normally based on this
* {@link CompletableFuture}.
* <p>
* <b>Only available on java 9</b>
*
* @return the new CompletionStage
* @since 1.0.0
* @see CompletableFuture#minimalCompletionStage()
* @see #asyncExec()
*/
default CompletionStage<Optional<T>> minimalCompletionStage​() {
throw new UnsupportedOperationException("Not available on java 8");
}
/**
* Waits if necessary for the produced future to complete, and then returns its
* result.
*
* @return the result value
* @throws CancellationException
* if the produced future was cancelled
* @throws ExecutionException
* if the produced future completed exceptionally
* @throws InterruptedException
* if the current thread was interrupted while waiting
* @see CompletableFuture#get()
* @see #asyncExec()
* @since 1.0.0
*/
default Optional<T> get() throws InterruptedException, ExecutionException {
return asyncExec().get();
}
}