Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright 2015 Peter Nerg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package javascalautils.concurrent;
import javascalautils.*;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static javascalautils.TryCompanion.*;
/**
* A Future that will hold the result of an asynchronous computation.
* The Future is paired with an instance of {@link Promise} which is also the way to get hold of a Future.
* One can see a Future as a holder for a value-to-be, not yet available but accessible sometime in the future.
* The preferred way to get hold of the value-to-be is to register a listener on any of the provided listener types since this allows for asynchronous non-blocking operations.
*
*
{@link #onComplete(Consumer)}
*
{@link #onSuccess(Consumer)}
*
{@link #onFailure(Consumer)}
*
* It is possible to register multiple listeners to several/same listener type.
* One can register a listener both before and after a Future has been completed.
* Should the Future already be completed when the listener is added it is fired immediately.
* The guarantee is that a listener is only fired once.
*
* All operations on this class are non-blocking, i.e. allowing for proper asynchronous/non-blocking programming patterns.
* With one exception, for situations where it is necessary to maintain synchronous/blocking behavior the method {@link #result(long, TimeUnit)} is provided.
*
* For real short and consistent programming one can use the {@link #apply(ThrowableFunction0)} method to provide a function that will be executed in the future.
* The result of the function will be reported to the Future returned by the method.
*
*
*
*
* Future<Integer> resultSuccess = Future.apply(() -> 9 / 3); // The Future will at some point contain: Success(3)
* Future<Integer> resultFailure = Future.apply(() -> 9 / 0); // The Future will at some point contain: Failure(ArithmeticException)
*
*
*
*
*
* @author Peter Nerg
* @since 1.2
* @param
* The type this Future will hold as result
*/
public interface Future {
/**
* Allows for easy creation of asynchronous computations that will be executed in the future.
* The method will use the {@link Executors#getDefault()} method to get hold of the default {@link Executor} to use for executing the provided job.
* Simple examples:
*
*
*
*
* Future<Integer> resultSuccess = Future.apply(() -> 9 / 3); // The Future will at some point contain: Success(3)
* Future<Integer> resultFailure = Future.apply(() -> 9 / 0); // The Future will at some point contain: Failure(ArithmeticException)
*
*
*
*
* @param
* The type for the Future
* @param function
* The function to render either the value T or raise an exception.
* @return The future that will hold the result provided by the function
* @since 1.3
*/
static Future apply(ThrowableFunction0 function) {
return apply(function, Executors.getDefault());
}
/**
* Allows for easy creation of asynchronous computations that will be executed in the future.
* The method will use the provided {@link Executor} for executing the provided job.
* Simple examples:
*
*
*
*
* Future<Integer> resultSuccess = Future.apply(() -> 9 / 3, someExecutor); // The Future will at some point contain: Success(3)
* Future<Integer> resultFailure = Future.apply(() -> 9 / 0, someExecutor); // The Future will at some point contain: Failure(ArithmeticException)
*
*
*
*
* @param
* The type for the Future
* @param function
* The function to render either the value T or raise an exception.
* @param executor
* The executor to use to compute/execute the Future holding the provided function
* @return The future that will hold the result provided by the function
* @since 1.4
*/
static Future apply(ThrowableFunction0 function, Executor executor) {
return executor.execute(promise -> promise.complete(Try(function)));
}
/**
* Creates a failed Future with the provided Throwable.
*
* @param
* The type for the Future
* @param throwable
* The throwable to complete the Future with.
* @return The completed Future holding the provided Throwable
* @since 1.5
*/
static Future failed(Throwable throwable) {
return fromTry(Failure(throwable));
}
/**
* Creates a successful Future with the provided value.
*
* @param
* The type for the Future
* @param value
* The value to complete the Future with.
* @return The completed Future holding the provided value
* @since 1.5
*/
static Future successful(T value) {
return fromTry(Success(value));
}
/**
* Creates a completed Future with the provided Try.
* The Future can therefore be either {@link Success} or {@link Failure}.
*
* @param
* The type for the Future
* @param result
* The {@link Success}/{@link Failure} to complete the Future with.
* @return The completed Future holding the provided result
* @since 1.5
*/
static Future fromTry(Try result) {
return new FutureImpl().complete(result);
}
/**
* Turns a Stream of Futures into a single Future containing a Stream with all the results from the Futures.
* Allows for easy management of multiple Futures.
* Note, should any Future in the Stream fail the entire sequence fails.
* An empty input Stream will result in a Future containing an empty result Stream.
*
* @param
* The type for the Stream in the resulting Future
* @param stream
* The Stream with Futures
* @return A single Future containing the Stream of results
* @since 1.5
*/
static Future> sequence(Stream> stream) {
return traverse(stream, f -> f);
}
/**
* Takes a Stream of values and applies the provided function to them in parallel resulting in a Future containing a Stream with the mapped values.
* Can be used to run a mapping operation in parallel e.g.:
*
* @param
* The type for the input Stream
* @param
* The type for the Stream in the resulting Future
* @param stream
* The Stream with values
* @param function
* The function to be applied to all values of the Stream
* @return A single Future containing the Stream of results
* @since 1.5
*/
static Future> traverse(Stream stream, Function> function) {
// map all Future to Future>
Stream>> mappedStream = stream.map(v -> function.apply(v)).map(f -> f.map(v -> Stream.of(v)));
// create the initial (complete) Future used by the reduction
// the Future is completed with an empty stream
// this is used as the base for the reduction, it will also be the result in case the input stream was empty
Future> initial = successful(Stream.empty());
// now it's a simple reduction of the stream
// for each found Future> we perform a flatMap with a map of the left/right Future creating a new single Future
return mappedStream.reduce(initial, (f1, f2) -> f1.flatMap(f1v -> f2.map(f2v -> Stream.concat(f1v, f2v))));
}
/**
* Check if this Future is completed, with a value or an exception.
*
* @return true if completed, false otherwise.
*/
boolean isCompleted();
/**
* The current (completed or not) value of the future.
* This is a non-blocking method, it will return the current state/value of the Future.
* There are three possible outcomes:
*
*
The future has not been completed -> {@link None} is returned
*
The execution of the Future was successful -> {@link Some} with a {@link Success} containing the value of the executed job
*
The execution failed and an exception was reported -> {@link Some} with a {@link Failure} containing the Throwable
*
*
* @return An {@link Option} with the result.
*/
Option> value();
/**
* Register a handler to be invoked if the Future gets completed with an exception.
* If the Future has already been completed the notification will happen in the current thread.
* Multiple handlers can be registered, without any guarantee of notification order.
* Each individual event handler will only be invoked once.
*
* @param failureHandler
* Consumer to invoke.
*/
void onFailure(Consumer failureHandler);
/**
* Register a handler to be invoked if the Future gets completed with a value.
* If the Future has already been completed the notification will happen in the current thread.
* Multiple handlers can be registered, without any guarantee of notification order.
* Each individual event handler will only be invoked once.
*
* @param successHandler
* Consumer to invoke.
*/
void onSuccess(Consumer successHandler);
/**
* Register a handler to be invoked if the Future gets completed with a value or a failure.
* If the Future has already been completed the notification will happen in the current thread.
* Multiple handlers can be registered, without any guarantee of notification order.
* Each individual event handler will only be invoked once.
*
* @param completeHandler
* Consumer to invoke.
*/
void onComplete(Consumer> completeHandler);
/**
* Asynchronously processes the value in the Future once it is available.
* Only successful Futures are reported to the consumer.
* This is pretty much the same as {@link #onSuccess(Consumer)} but is here for completion keeping a consistent look and feel.
*
* @param consumer
* The consumer to digest the result
*/
void forEach(Consumer consumer);
/**
* Creates a new {@link Future} that will hold the mapped successful value of this instance once it is completed.
* Unsuccessful Futures will not be mapped, they are kept unsuccessful as they are.
*
* @param
* The type for the value held by the mapped future
* @param function
* The function to apply
* @return The mapped Future
*/
Future map(ThrowableFunction1 function);
/**
* Creates a new {@link Future} that will hold the mapped successful value of this instance once it is completed.
* Unsuccessful Futures will not be mapped, they are kept unsuccessful as they are.
*
* @param
* The type for the value held by the mapped future
* @param function
* The function to apply
* @return The mapped Future
*/
Future flatMap(ThrowableFunction1> function);
/**
* Creates a new {@link Future} that will filter the successful value of this instance once it is completed.
* The possible outcomes are:
*
*
This Future is successful -> predicate matches -> The filtered future is completed with the value.
*
This Future is successful -> predicate fails -> The filtered future is failed with NoSuchElementException.
*
This Future is failure -> The failure is passed on to the filtered Future.
*
*
* @param predicate
* The predicate to apply
* @return The filtered Future
*/
Future filter(Predicate predicate);
/**
* Creates a new {@link Future} that will hold the transformed successful value of this instance once it is completed.
* Successful futures are transformed with the onSuccess function and unsuccessful/failure futures are transformed with onFailure.
*
* @param
* The type for the value held by the mapped future
* @param onSuccess
* The function to apply on a 'successful' result
* @param onFailure
* The function to apply on a 'failure' result
* @return The mapped Future
* @since 1.3
*/
Future transform(ThrowableFunction1 onSuccess, ThrowableFunction1 onFailure);
/**
* Creates a new {@link Future} that in case this {@link Future} is a 'failure' will apply the function to recover the 'failure' to a 'success'.
* Should this {@link Future} be a 'success' the value is propagated as-is.
* E.g.
*
*
*
* In case of 'future' being successful then that value is passed on to 'recovered', in case of failure then the recover function kicks in and returns the message from the throwable.
*
*
* @param recoverFunction
* The function to apply in case of a 'failure'
* @return The recovered Future
* @since 1.3
*/
Future recover(ThrowableFunction1 recoverFunction);
/**
* Blocks and waits for this Future to complete.
* Returns the result of a successful Future or throws the exception in case of a failure.
* The methods blocks for at most the provided duration.
* If the Future is already completed the method returns immediately.
*
* @param duration
* The duration to block
* @param timeUnit
* The unit for the duration
* @return The result in case successful
* @throws Throwable
* The error reported in case of a failure
* @throws TimeoutException
* In case the waiting time is passed
*/
T result(long duration, TimeUnit timeUnit) throws Throwable, TimeoutException;
/**
* Blocks and waits for this Future to complete.
* Returns the result of a successful Future or throws the exception in case of a failure.
* The methods blocks for at most the provided duration.
* If the Future is already completed the method returns immediately.
*
* @param duration
* The duration to block
* @return The result in case successful
* @throws Throwable
* The error reported in case of a failure
* @throws TimeoutException
* In case the waiting time is passed
* @since 1.8
*/
default T result(Duration duration) throws Throwable, TimeoutException {
Validator.requireNonNull(duration, "Null is not a valid Duration");
return result(duration.toMillis(), TimeUnit.MILLISECONDS);
}
/**
* Blocks and waits for this Future to complete.
* As opposed to {@link #result(long, TimeUnit) result} this method will not return the value or throw the exception of the Future.
* The method will upon completion returns this.
* The purpose of the method is to provide a blocking mechanism waiting for the Future to complete.
* Any action on the Future's result is then left to the developer to manage.
*
* @param duration
* The duration to block
* @param timeUnit
* The unit for the duration
* @return this if the Future completes within the specified time
* @throws TimeoutException
* In case the waiting time is passed
* @throws InterruptedException
* In case the thread gets interrupted during the wait
* @since 1.8
*/
Future ready(long duration, TimeUnit timeUnit) throws TimeoutException, InterruptedException;
/**
* Blocks and waits for this Future to complete.
* As opposed to {@link #result(long, TimeUnit) result} this method will not return the value or throw the exception of the Future.
* The method will upon completion returns this.
* The purpose of the method is to provide a blocking mechanism waiting for the Future to complete.
* Any action on the Future's result is then left to the developer to manage.
*
* @param duration
* The duration to block
* @return this if the Future completes within the specified time
* @throws TimeoutException
* In case the waiting time is passed
* @throws InterruptedException
* In case the thread gets interrupted during the wait
* @since 1.8
*/
default Future ready(Duration duration) throws TimeoutException, InterruptedException {
Validator.requireNonNull(duration, "Null is not a valid Duration");
return ready(duration.toMillis(), TimeUnit.MILLISECONDS);
}
}