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.function.Consumer;
import java.util.function.Function;
import io.vlingo.common.completes.SinkAndSourceBasedCompletes;
import io.vlingo.common.completes.exceptions.FailedOperationException;
/**
* {@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 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) {
if (SinkAndSourceBasedCompletes.isToggleActive()) {
return SinkAndSourceBasedCompletes.withScheduler(scheduler);
}
return new BasicCompletes(scheduler);
}
static Completes noTimeout() {
return new BasicCompletes((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) {
if (SinkAndSourceBasedCompletes.isToggleActive()) {
return SinkAndSourceBasedCompletes.withScheduler(new Scheduler()).with(outcome);
}
return new BasicCompletes(outcome, true);
}
/**
* 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) {
if (SinkAndSourceBasedCompletes.isToggleActive()) {
SinkAndSourceBasedCompletes completes = SinkAndSourceBasedCompletes
.withScheduler(new Scheduler());
completes.source.emitError(new FailedOperationException(outcome));
return completes;
}
return new BasicCompletes(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) {
if (SinkAndSourceBasedCompletes.isToggleActive()) {
return SinkAndSourceBasedCompletes.withScheduler(scheduler);
}
return new RepeatableCompletes(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) {
if (SinkAndSourceBasedCompletes.isToggleActive()) {
return SinkAndSourceBasedCompletes.withScheduler(new Scheduler()).with(outcome);
}
return new RepeatableCompletes(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) {
if (SinkAndSourceBasedCompletes.isToggleActive()) {
Completes failure = SinkAndSourceBasedCompletes.withScheduler(new Scheduler()).with(outcome);
failure.failed();
return failure;
}
return new RepeatableCompletes(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);
}
/**
* 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
* @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 the O type of outcome
* @return O
*/
O await();
/**
* Answer the {@code O} outcome after blocking for a maximum of
* {@code timeout} milliseconds for completion.
* @param timeout the long maximum number of milliseconds to block for an outcome
* @param the O type of outcome
* @return O
*/
O await(final long timeout);
/**
* Answer whether or not this {@code Completes} has completed.
* @return boolean
*/
boolean isCompleted();
/**
* Answer whether or not this {@code Completes} has failed.
* @return boolean
*/
boolean hasFailed();
/**
* Cause this {@code Completes} to fail, unless it has already completed.
*/
void failed();
/**
* Answer whether or not this {@code Completes} has an available outcome,
* which will be true for either success or failure.
* @return boolean
*/
boolean hasOutcome();
/**
* Answer my {@code outcome}, which may be a unknown, success, or failure.
* @return T
*/
T outcome();
/**
* Answer myself after I am prepared to handle the next outcome. By default
* this throws {@code UnsupportedOperationException}, but will provided intended
* behavior and answer if the underlying type is {@code RepeatableCompletes}. Use
* {@link Completes#repeatableUsing(Scheduler)} to create a valid instance.
* @return {@code Completes}
*/
Completes repeat();
/**
* Answer myself after setting my {@code outcome}. This should normally be used only
* by internal operations or when available through an actor for its results.
* @param outcome the O typed outcome to set as my outcome
* @param the type to be answered
* @return {@code Completes}
*/
Completes with(final O outcome);
}