All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zodiac.sdk.async.promises.package.html Maven / Gradle / Ivy



    
        Async Promises API
        
        
    
    
        

Async Promises API

Asynchronous promises use the "promise" idiom to handle the case where the logic that does the work may be asynchronous and will not complete synchronously. The logic of an AsyncPromise is passed a "trigger" object which it will call when the work has either succeeded or failed.

The library makes no assumptions that it knows how to run the logic that will be run - whatever it is simply calls the trigger when the work is complete. So it is suitable for making calls to external asynchronus libraries where you don't control how or on what thread the subsequent logic will be run.

Use Case

It is not uncommon to have more than one callback-based library to wire together, or to have a sequence of asynchronous callbacks you want to execute, with a guarantee that they are all executed or you get notified in the case of failure. In asynchronous libraries, it is common that they provide the plumbing that actually runs your callback, so promises shouldn't make an assumption that they can throw stuff in a thread pool to run themselves.

This library can be used for synchronous promises as well - just call the passed trigger's trigger() method synchronously for that.

Usage

The basic way to use this library is to implement the class Logic or SimpleLogic, and pass that to the static AsyncPromise.create() method. The Logic interface is a functional interface which simply takes an input parameter and a trigger and a context (see below), and does something, which might be synchronous or asynchronous, but in either case, ends with a call to the trigger object to provide the results and possibly trigger the next promise to do something with that output, if running in a chain.

The logic will not actually be run until the Promise's start() method is called (you pass it the initial input, which will be passed to your Logic implementation).

Chaining

AsyncPromises can be chained together, and one can accept as input the output of a previous one. The result of chaining (using AsyncPromise's then() method is a new AsyncPromise which takes the original one's input type as input, and outputs the output type of the Logic or AsyncPromise instance you just passed.

So, if you start with:

            AsyncPromise<A,B>
        

and call then on it with a new Logic or promise parameterized on B, C, you get:

            AsyncPromise<A,B> first = ...;
            AsyncPromise<A,C> chained = first.then(new Logic<B, C>() { ... });
        
or using lambdas
            AsyncPromise<A,C> chained = first.then((B data, Trigger<C> next) -> { ... });
        

and when you call first.start(someA), the first and second will be run (you can pass an optional Trigger object to start() to collect the final results).

If you want to chain together promises of heterogenous types, simply use the then() method that takes an input argument:

            AsyncPromise<A,B> first = ...;
            AsyncPromise<B,C> second = ...;
            AsyncPromise<Q,R> third = ...;
            AsyncPromise<A,R> chained = first.then(second).then(new Q(), third);
        
and then to actually execute all of the logic in sequence,
            A a = ...;
            chained.start(a);
        

Promise Context

The PromiseContext provides a way for decoupled Logic instances to communicate between themselves. It is passed to Logic's method. Key objects - PromiseContext.Key - are used to store and retrieve data from it. The key instance must be known to both Logics:

            static Key<String> NAME_KEY = PromiseContext.key(String.class);

            AsyncPromise<A,B>.create((A data, Trigger<B> trigger, PromiseContext context) -> {
                String interestingString = ...;
                context.put(key, interestingString);
                ...
            });
            AsyncPromise<B,C>.create((A data, Trigger<C> trigger, PromiseContext context) -> {
                String interestingString = context.get(NAME_KEY);
                ...
            });
        

Failure Handling

The FailureHandler lets you handle errors that occured during asynchronous processing. So you can attach a FailureHandler to a promise, and it will be notified in the case of failure.

When building a chain of promises, multiple failure handlers may be attached to different steps in the promise; on failure, the failure propagates backward to the nearest handler, which can return true from its onFailure method to indictate the failure should continue propagating backward to earlier failure handlers.

A failure consists of either passing a Throwable to the trigger, or throwing an exception during logic execution.





© 2015 - 2024 Weber Informatics LLC | Privacy Policy