io.vlingo.common.Completes Maven / Gradle / Ivy
Show all versions of vlingo-common Show documentation
// Copyright © 2012-2020 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.
package io.vlingo.common;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.Function;
import io.vlingo.common.completes.FutureCompletes;
/**
* {@code Completes} models the eventual completion of an asynchronous operation
* that has an answer (return value) of a specific type. You will find this
* similar to {@code Future} and {@code CompletableFuture} from the Java platform. Yet,
* {@code Completes} is designed for non-blocking and is typically used in
* that manner. There is a means to explicitly block on the outcome but
* this is used only for testing.
*
*
* Use {@code Completes} beyond handling the eventual outcome of asynchronous outcomes.
* For example, use a pipeline of multiple {@code Completes} when you must send a number
* of asynchronous messages for multiple outcomes, but each outcome must precede the next.
* Thus, while each message send is entirely asynchronous, {@code Completes} manages the
* sequencing of each message and its outcome with the possibility of each outcome being used
* for the next message send. {@code Completes} is a monad.
*
*
* reservations
* .reserveTravel(ticketingDetails)
* .andThenTo(reservation -> booking.record(reservation))
* .andThenTo(bookingRecord -> traveler.bookFor(bookingRecord))
* .andThenTo(points -> rewards.credit(points));
*
*
*
* Note that the various forms of {@code andThenTo()} pipeline using a nested {@code Completes}
* instance, making it possible for the registered {@code Function} to send an asynchronous
* message to an actor with without damaging the parent {@code Completes}. Using {@code andThen()}
* to send an asynchronous message to an actor will have undefined results.
*
* Note that the {@code Completes} doesn't necessarily need to be executed when there is an outcome
* if there is no subscription to it. Deciding when to run is implementation dependent, and is encouraged
* to subscribe to the {@code Completes} using the {@code andFinallyConsume} method.
*
* @param the type that is expected as the outcome (return value)
*/
public interface Completes {
/**
* Answer a new {@code CompletesId} that is the {@code id} value.
* @param id the String to use as the value
* @return CompletesId
*/
static CompletesId completesId(final String id) {
return new CompletesId(id);
}
/**
* Answer a new {@code CompletesId}.
* @return CompletesId
*/
static CompletesId completesId() {
return new CompletesId();
}
/**
* Answer a new {@code CompletesId} that is the next available.
* @return {@code CompletesId}
*/
static CompletesId nextCompletesId() {
return new CompletesId();
}
/**
* Answer a new {@code Completes}. The instance has not
* completed at the time of creation.
* @return {@code Completes}
*/
static Completes asByte() {
return new FutureCompletes<>();
}
/**
* Answer a new {@code Completes}. The instance has not
* completed at the time of creation.
* @return {@code Completes}
*/
static Completes asCharacter() {
return new FutureCompletes<>();
}
/**
* Answer a new {@code Completes}. The instance has not
* completed at the time of creation.
* @return {@code Completes}
*/
static Completes asDouble() {
return new FutureCompletes<>();
}
/**
* Answer a new {@code Completes}. The instance has not
* completed at the time of creation.
* @return {@code Completes}
*/
static Completes asFloat() {
return new FutureCompletes<>();
}
/**
* Answer a new {@code Completes}. The instance has not
* completed at the time of creation.
* @return {@code Completes}
*/
static Completes asInteger() {
return new FutureCompletes<>();
}
/**
* Answer a new {@code Completes}. The instance has not
* completed at the time of creation.
* @return {@code Completes}
*/
static Completes asLong() {
return new FutureCompletes<>();
}
/**
* Answer a new {@code Completes}. The instance has not
* completed at the time of creation.
* @return {@code Completes}
*/
static Completes asShort() {
return new FutureCompletes<>();
}
/**
* Answer a new {@code Completes}. The instance has not
* completed at the time of creation.
* @return {@code Completes}
*/
static Completes asString() {
return new FutureCompletes<>();
}
/**
* Answer a new {@code Completes}. The instance has not
* completed at the time of creation.
* @param the T typed outcome of the Completes
* @return {@code Completes}
*/
static Completes asTyped() {
return new FutureCompletes<>();
}
/**
* Answer a new {@code Completes} that uses the {@code scheduler}. The
* instance has not completed at the time of creation.
* @param id the CompletesId to assign to the new {@code Completes} instance
* @param scheduler the Scheduler to use for timeouts
* @param the T typed outcome of the Completes
* @return {@code Completes}
*/
static Completes using(final CompletesId id, final Scheduler scheduler) {
return new FutureCompletes<>(id, scheduler);
}
/**
* Answer a new {@code Completes} that uses the {@code scheduler}. The
* instance has not completed at the time of creation.
* @param scheduler the Scheduler to use for timeouts
* @param the T typed outcome of the Completes
* @return {@code Completes}
*/
static Completes using(final Scheduler scheduler) {
return new FutureCompletes<>(scheduler);
}
static Completes noTimeout() {
return new FutureCompletes<>((Scheduler) null);
}
/**
* Answer a new {@code Completes} that has a successful {@code outcome}.
* The instance has already completed at the time of creation,
* which means that any function/accessor used to read the
* successful {@code outcome} will be immediate.
* @param outcome the T typed outcome answer (return value)
* @param the T typed outcome of the Completes
* @return {@code Completes}
*/
static Completes withSuccess(final T outcome) {
return new FutureCompletes<>(outcome);
}
/**
* Answer a new {@code Completes} that has a failure {@code outcome}.
* The instance has already completed at the time of creation,
* which means that any function/accessor used to read the
* failure {@code outcome} will be immediate.
* @param outcome the T typed outcome answer (return value)
* @param the T typed outcome of the Completes
* @return {@code Completes}
*/
static Completes withFailure(final T outcome) {
return new FutureCompletes<>(outcome, false);
}
/**
* Answer a new {@code Completes} that has a failure outcome of {@code null}.
* The instance has already completed at the time of creation,
* which means that any function/accessor used to read the
* failure {@code outcome} will be immediate.
* @param the T typed outcome of the Completes
* @return {@code Completes}
*/
static Completes withFailure() {
return withFailure(null);
}
/**
* Answer a new {@code Completes} that is repeatable, meaning that
* following a given completion the instance may be reused to
* achieve one or more subsequent eventual outcomes. To do so
* use {@link Completes#repeat()} to prepare for the next outcome.
* The instance has not completed at the time of creation.
* @param scheduler the Scheduler to use for timeouts
* @param the T typed outcome of the Completes
* @see Completes#repeat()
* @return {@code Completes}
*/
static Completes repeatableUsing(final Scheduler scheduler) {
return new FutureCompletes<>(scheduler);
}
/**
* Answer a new {@code Completes} that is repeatable, meaning that
* following a given completion the instance may be reused to
* achieve one or more subsequent eventual outcomes. To do so
* use {@link Completes#repeat()} to prepare for the next outcome.
* The instance has already completed successfully at the time of creation.
* @param outcome the T typed outcome answer (return value) of {@code null}
* @param the T typed outcome of the Completes
* @see Completes#repeat()
* @return {@code Completes}
*/
static Completes repeatableWithSuccess(final T outcome) {
return new FutureCompletes<>(outcome, true);
}
/**
* Answer a new {@code Completes} that is repeatable, meaning that
* following a given completion the instance may be reused to
* achieve one or more subsequent eventual outcomes. To do so
* use {@link Completes#repeat()} to prepare for the next outcome.
* The instance has already completed with failure at the time of creation.
* @param outcome the T typed outcome answer (return value) of {@code null}
* @param the T typed outcome of the Completes
* @see Completes#repeat()
* @return {@code Completes}
*/
static Completes repeatableWithFailure(final T outcome) {
return new FutureCompletes<>(outcome, false);
}
/**
* Answer a new {@code Completes} that is repeatable, meaning that
* following a given completion the instance may be reused to
* achieve one or more subsequent eventual outcomes. To do so
* use {@link Completes#repeat()} to prepare for the next outcome.
* The instance has already completed with failure of {@code null} at the
* time of creation.
* @param the T typed outcome of the Completes
* @see Completes#repeat()
* @return {@code Completes}
*/
static Completes repeatableWithFailure() {
return repeatableWithFailure(null);
}
/**
* Inverts an {@code Outcome} of {@code Completes}
* to a {@code Completes} of {@code Outcome}.
*
* @param outcome the {@code Outcome>} that will be inverted
* @param the type of the Failure
* @param the type of the Success
* @return {@code Completes>}
*/
static Completes> invert(final Outcome> outcome) {
return outcome.resolve(
e -> Completes.withFailure(Failure.of(e)),
s -> {
if (s.hasFailed()) {
return Completes.withFailure(Success.of(s.outcome()));
}
return s.andThenTo(result -> Completes.withSuccess(Success.of(result)));
});
}
/**
* Answer the {@code Completes} instance after registering the {@code function} to be used to
* apply the value of type {@code O} when it is available, along with the {@code timeout} and
* {@code failedOutcomeValue}. Note that failure is different from exceptional outcomes,
* which are handled by {@link Completes#recoverFrom(Function)}.
*
* Note that you must not use any form of {@code andThen()} to send a message to an actor. See
* {@link Completes#andThenTo(long, Object, Function)} for that.
* @param timeout the long number of milliseconds until this {@code Completes} is considered timed out
* @param failedOutcomeValue the O typed value answered in the case of failure, including for timeout
* @param function the {@code Function} to receive the {@code Completes} of the async operation and to produce the {@code Completes} of the next operation
* @param the O typed outcome of the Completes, which may be different from T
* @return {@code Completes}
*/
Completes andThen(final long timeout, final O failedOutcomeValue, final Function function);
/**
* Answer the {@code Completes} instance after registering the {@code function} to be used to
* apply the value of type {@code O} when it is available, along with the {@code failedOutcomeValue}.
* There is no timeout specified in this operation, meaning that the outcome could be
* infinite. Note that failure is different from exceptional outcomes, which are handled by
* {@link Completes#recoverFrom(Function)}.
*
* Note that you must not use any form of {@code andThen()} to send a message to an actor. See
* {@link Completes#andThenTo(Object, Function)} for that.
* @param failedOutcomeValue the O typed value answered in the case of failure
* @param function the {@code Function} to receive the {@code Completes} of the async operation and to produce the {@code Completes} of the next operation
* @param the O typed outcome of the Completes, which may be different from T
* @return {@code Completes}
*/
Completes andThen(final O failedOutcomeValue, final Function function);
/**
* Answer the {@code Completes} instance after registering the {@code function} to be used to
* apply the value of type {@code O} when it is available, along with the {@code timeout} and a
* failed outcome value of {@code null}. Note that failure is different from exceptional outcomes,
* which are handled by {@link Completes#recoverFrom(Function)}.
*
* Note that you must not use any form of {@code andThen()} to send a message to an actor. See
* {@link Completes#andThenTo(long, Function)} for that.
* @param timeout the long number of milliseconds until this {@code Completes} is considered timed out
* @param function the {@code Function} to receive the {@code Completes} of the async operation and to produce the {@code Completes} of the next operation
* @param the O typed outcome of the Completes, which may be different from T
* @return {@code Completes}
*/
Completes andThen(final long timeout, final Function function);
/**
* Answer the {@code Completes} instance after registering the {@code function} to be used to
* apply the value of type {@code O} when it is available. There is no {@code timeout} and a
* failed outcome value of {@code null}. Note that failure is different from exceptional outcomes,
* which are handled by {@link Completes#recoverFrom(Function)}.
*
* Note that you must not use any form of {@code andThen()} to send a message to an actor. See
* {@link Completes#andThenTo(Function)} for that.
* @param function the {@code Function} to receive the {@code Completes} of the async operation and to produce the {@code Completes} of the next operation
* @param the O typed outcome of the Completes, which may be different from T
* @return {@code Completes}
*/
Completes andThen(final Function function);
/**
* Answer the {@code Completes} instance after registering the {@code consumer} to be used to
* accept the value of type {@code T} when it is available, along with the {@code timeout} and
* {@code failedOutcomeValue}. Note that failure is different from exceptional outcomes,
* which are handled by {@link Completes#recoverFrom(Function)}.
* @param timeout the long number of milliseconds until this {@code Completes} is considered timed out
* @param failedOutcomeValue the T typed value answered in the case of failure, including for timeout
* @param consumer the {@code Consumer} to receive the {@code Completes} of the async operation
* @return {@code Completes}
*/
Completes andThenConsume(final long timeout, final T failedOutcomeValue, final Consumer consumer);
/**
* Answer the {@code Completes} instance after registering the {@code consumer} to be used to
* accept the value of type {@code T} when it is available, along with the {@code failedOutcomeValue}.
* There is no timeout specified in this operation, meaning that the outcome could be
* infinite. Note that failure is different from exceptional outcomes, which are handled by
* {@link Completes#recoverFrom(Function)}.
* @param failedOutcomeValue the T typed value answered in the case of failure
* @param consumer the {@code Consumer} to receive the {@code Completes} of the async operation
* @return {@code Completes}
*/
Completes andThenConsume(final T failedOutcomeValue, final Consumer consumer);
/**
* Answer the {@code Completes} instance after registering the {@code consumer} to be used to
* accept the value of type {@code T} when it is available, along with the {@code timeout} and a
* failed outcome value of {@code null}. Note that failure is different from exceptional outcomes,
* which are handled by {@link Completes#recoverFrom(Function)}.
* @param timeout the long number of milliseconds until this {@code Completes} is considered timed out
* @param consumer the {@code Consumer} to receive the {@code Completes} of the async operation
* @return {@code Completes}
*/
Completes andThenConsume(final long timeout, final Consumer consumer);
/**
* Answer the {@code Completes} instance after registering the {@code consumer} to be used to
* accept the value of type {@code T} when it is available. There is no {@code timeout} and a
* failed outcome value of {@code null}. Note that failure is different from exceptional outcomes,
* which are handled by {@link Completes#recoverFrom(Function)}.
* @param consumer the {@code Consumer} to receive the {@code Completes} of the async operation
* @return {@code Completes}
*/
Completes andThenConsume(final Consumer consumer);
/**
* Answer the {@code O} instance after registering the {@code function} to be used to
* apply the value of type {@code O} when it is available, along with the {@code timeout} and
* {@code failedOutcomeValue}. Note that failure is different from exceptional outcomes,
* which are handled by {@link Completes#recoverFrom(Function)}.
*
* Note that {@code andThenTo()} pipelines using a nested {@code Completes} instance, making it possible
* for the registered {@code Function} to send an asynchronous message to an actor with without damaging
* the parent {@code Completes}. Using {@code andThen()} to send an asynchronous message to an actor will
* have undefined results.
* @param timeout the long number of milliseconds until this {@code Completes} is considered timed out
* @param failedOutcomeValue the F typed value answered in the case of failure, including for timeout
* @param function the {@code Function} to receive the {@code Completes} of the async operation and to produce the {@code O} outcome
* @param the F type of the failedOutcomeValue
* @param the O typed outcome, which may be different from T and may be a Completes
* @return O
*/
O andThenTo(final long timeout, final F failedOutcomeValue, final Function function);
/**
* Answer the {@code O} instance after registering the {@code function} to be used to
* apply the value of type {@code T} when it is available, along with the {@code failedOutcomeValue}.
* There is no timeout specified in this operation, meaning that the outcome could be
* infinite. Note that failure is different from exceptional outcomes, which are handled by
* {@link Completes#recoverFrom(Function)}.
*
* Note that {@code andThenTo()} pipelines using a nested {@code Completes} instance, making it possible
* for the registered {@code Function} to send an asynchronous message to an actor with without damaging
* the parent {@code Completes}. Using {@code andThen()} to send an asynchronous message to an actor will
* have undefined results.
* @param failedOutcomeValue the F typed value answered in the case of failure
* @param function the {@code Function} to receive the {@code Completes} of the async operation and to produce the {@code O} outcome
* @param the F type of the failedOutcomeValue
* @param the O typed outcome, which may be different from T and may be a Completes
* @return O
*/
O andThenTo(final F failedOutcomeValue, final Function function);
/**
* Answer the {@code O} instance after registering the {@code function} to be used to
* apply the value of type {@code T} when it is available, along with the {@code timeout} and a
* failed outcome value of {@code null}. Note that failure is different from exceptional outcomes,
* which are handled by {@link Completes#recoverFrom(Function)}.
*
* Note that {@code andThenTo()} pipelines using a nested {@code Completes} instance, making it possible
* for the registered {@code Function} to send an asynchronous message to an actor with without damaging
* the parent {@code Completes}. Using {@code andThen()} to send an asynchronous message to an actor will
* have undefined results.
* @param timeout the long number of milliseconds until this {@code Completes} is considered timed out
* @param function the {@code Function} to receive the {@code Completes} of the async operation and to produce the {@code O} outcome
* @param the O typed outcome, which may be different from T and may be a Completes
* @return O
*/
O andThenTo(final long timeout, final Function function);
/**
* Answer the {@code O} instance after registering the {@code function} to be used to
* apply the value of type {@code O} when it is available. There is no {@code timeout} and a
* failed outcome value of {@code null}. Note that failure is different from exceptional outcomes,
* which are handled by {@link Completes#recoverFrom(Function)}.
*
* Note that {@code andThenTo()} pipelines using a nested {@code Completes} instance, making it possible
* for the registered {@code Function} to send an asynchronous message to an actor with without damaging
* the parent {@code Completes}. Using {@code andThen()} to send an asynchronous message to an actor will
* have undefined results.
* @param function the {@code Function} to receive the {@code Completes} of the async operation and to produce the O of the next operation
* @param the O typed outcome, which may be different from T and may be a Completes
* @return O
*/
O andThenTo(final Function function);
/**
* Answer the {@code Completes} after registering the {@code function} to be used to
* apply the failure outcome if such occurs.
* @param function the {@code Function} to receive the {@code Completes} of the async operation and to produce the {@code Completes} of the next operation
* @param the expected error type
* @return {@code Completes}
*/
Completes otherwise(final Function function);
/**
* Answer the {@code Completes} after registering the {@code consumer} to be used to
* accept the failure outcome if such occurs.
* @param consumer the {@code Consumer} to receive the {@code Completes} of the async operation and to produce the {@code Completes} of the next operation
* @return {@code Completes}
*/
Completes otherwiseConsume(final Consumer consumer);
/**
* Answer the {@code Completes} after registering the {@code function} to be used to
* apply the exceptional outcome if such occurs.
* @param function the {@code Function} to receive the {@code Completes} of the async operation and to produce the {@code Completes} of the next operation
* @return {@code Completes}
*/
Completes recoverFrom(final Function function);
/**
* Answer the {@code O} outcome as the final implicit function in a pipeline.
* Subscribes to the current {@code Completes} and runs if the outcome is successful.
*
* Note that you must have either {@code andFinally()} or {@code andFinallyConsume()} as
* a terminator for your pipeline, or the {@code Completes} will never run.
*
* @param the O type of outcome from the function
* @return {@code Completes}
*/
Completes andFinally();
/**
* Answer the {@code O} outcome as the final function in a pipeline.
* Subscribes to the current {@code Completes} and runs if the outcome is successful.
*
* Note that you must have either {@code andFinally()} or {@code andFinallyConsume()} as
* a terminator for your pipeline, or the {@code Completes} will never run.
*
* @param function the {@code Function} that will receive the successful value, if any.
* @param the O type of outcome from the function
* @return {@code Completes}
*/
Completes andFinally(final Function function);
/**
* Subscribes to the current {@code Completes} and runs if the outcome is successful.
*
* Note that you must have either {@code andFinally()} or {@code andFinallyConsume()} as
* a terminator for your pipeline, or the {@code Completes} will never run.
*
* @param consumer the {@code Consumer} that will receive the successful value, if any.
*/
void andFinallyConsume(final Consumer consumer);
/**
* Answer the {@code O} outcome after blocking indefinitely for completion.
* @param