org.zodiac.sdk.async.promises.AsyncPromise Maven / Gradle / Ivy
package org.zodiac.sdk.async.promises;
import org.zodiac.sdk.async.promises.PromiseContext.Key;
/**
* An asynchronous promise. Unlike traditional promises that can be chained
* together, these promises expect to that the logic they will trigger runs
* asynchronously, and that continuing the chain of promises will occur some
* time in the future.
*
* Promises can be chained together.
*
* Asynchronous promises have a PromiseContext which can be used to pass
* additional objects along the chain of promises.
*
*
*/
public abstract class AsyncPromise {
public static AsyncPromise create(Logic toRun) {
return new PromiseImpl<>(toRun);
}
public static AsyncPromise create(SimpleLogic toRun) {
return new PromiseImpl<>(toRun);
}
abstract Key key();
/**
* Run the promise, invoking the passed trigger with a result when the work
* has completed.
* @param input The input data
* @param onDone The trigger
* @return This.
*/
public abstract AsyncPromise start(T input, Trigger onDone);
/**
* Run the promise, using a no-op trigger, for promises that do not
* need to pass back a result.
* @param input The input
* @return This.
*/
public final AsyncPromise start(final T input) {
AsyncPromise.this.start(input, new Trigger() {
@Override
public void trigger(R obj, Throwable thrown) {
if (thrown != null) {
failed(thrown, key(), input);
}
}
});
return this;
}
/**
* Run the promise, using null as input (useful for instances whose
* first type parameter is void).
*
* @return This.
*/
public final AsyncPromise, R> start() {
return start(null);
}
/**
* Use this key to attach the input to the promise context. If set,
* the input parameter will be automatically added to the context before
* subsequent promises are called.
*
* @param key They key
* @return This.
*/
public abstract AsyncPromise usingKey(PromiseContext.Key key);
/**
* Run an additional promise with new input data when this one
* completes.
*
* @param The input type to the next promise
* @param The output type of the next promise
* @param q The input to the next promise
* @param p The next promise
* @return A promise that merges this and the passed one
*/
public final AsyncPromise then(final Q q, final AsyncPromise p) {
AsyncPromise interim = new PromiseImpl<>(new Logic() {
@Override
public void run(R data, Trigger next, PromiseContext context) throws Exception {
next.trigger(q, null);
}
});
return this.then(interim).then(p);
}
/**
* Run an additional promise with new input data when this one
* completes.
*
* @param The input type to the next promise
* @param The output type of the next promise
* @param q The input to the next promise
* @param logic p The next unit of logic to run
* @return A promise that merges this and the passed one
*/
public final AsyncPromise then(final Q q, final Logic logic) {
AsyncPromise promise = new PromiseImpl<>(logic);
return then(q, promise);
}
/**
* Chain another promise to be run against the output of this one.
*
* @param The type of the next promise's output
* @param logic The next promise
* @return A promise which combine this and the next one
*/
public abstract AsyncPromise then(AsyncPromise logic);
/**
* Chain another promise to be run against the output of this one.
*
* @param The type of the next promise's output
* @param next The logic to run against this promise's result
* @return A promise which combine this and the next one
*/
public final AsyncPromise then(final SimpleLogic next) {
return then(new Logic(){
@Override
public void run(R data, Trigger trigger, PromiseContext context) throws Exception {
next.run(data, trigger);
}
});
}
/**
* Chain another promise to be run against the output of this one.
*
* @param The type of the next promise's output
* @param next The logic to run against this promise's result
* @return A promise which combine this and the next one
*/
public final AsyncPromise then(Logic next) {
AsyncPromise p = new PromiseImpl<>(next);
return then(p);
}
abstract void setParent(AsyncPromise, T> parent);
abstract void failed(Throwable thrown, PromiseContext.Key key, R input);
/**
* Attach a failure handler to handle asynchronous failures.
* The handler will be notified if promise execution is aborted
* because of an error, and may run cleanup logic or whatever
* is necessary.
*
* If multiple faiure handlers are added at different points in
* assembling a chain of AsyncPromises, the one nearest to the
* failure will be called first; if it returns true, earlier
* failure handlers will also be notified - the failure notification
* propagates backward toward the beginning of the chain.
*
*
* @param failure The handler
* @return This.
*/
public abstract AsyncPromise onFailure(FailureHandler failure);
abstract boolean hasFailureHandler();
abstract PromiseContext context();
}