Package ratpack.exec

Interface Promise<T>

  • Type Parameters:
    T - the type of promised value

    public interface Promise<T>
    A promise for a single value.

    A promise is a representation of a value which will become available later. Methods such as map(Function), flatMap(Function), cache() etc.) allow a pipeline of “operations” to be specified, that the value will travel through as it becomes available. Such operations are implemented via the transform(Function) method. Each operation returns a new promise object, not the original promise object.

    To create a promise, use the async(Upstream) method (or one of the variants such as sync(Factory). To test code that uses promises, use the ExecHarness.

    The promise is not “activated” until the then(Action) method is called. This method terminates the pipeline, and receives the final value.

    Promise objects are multi use. Every promise pipeline has a value producing function at its start. Activating a promise (i.e. calling then(Action)) invokes the function. The cache() operation can be used to change this behaviour.

    • Method Detail

      • async

        static <T> Promise<T> async​(Upstream<T> upstream)
        Creates a promise for value that will be produced asynchronously.

        The Upstream.connect(Downstream) method of the given upstream will be invoked every time the value is requested. This method should propagate the value (or error) to the given downstream object when it is available.

        
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String[] args) throws Exception {
             String value = ExecHarness.yieldSingle(e ->
               Promise.<String>async(down ->
                 new Thread(() -> {
                   down.success("foo");
                 }).start()
               )
             ).getValueOrThrow();
        
             assertEquals(value, "foo");
           }
         }
         
        Type Parameters:
        T - the type of promised value
        Parameters:
        upstream - the producer of the value
        Returns:
        a promise for the asynchronously created value
        Since:
        1.3
        See Also:
        Upstream, sync(Factory), value(Object), error(Throwable)
      • sync

        static <T> Promise<T> sync​(Factory<T> factory)
        Creates a promise for the value synchronously produced by the given factory.

        The given factory will be invoked every time that the value is requested. If the factory throws an exception, the promise will convey that exception.

        
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String[] args) throws Exception {
             String value = ExecHarness.yieldSingle(e ->
               Promise.sync(() -> "foo")
             ).getValueOrThrow();
        
             assertEquals(value, "foo");
           }
         }
         

        This method is often used to when a method needs to return a promise, but can produce its value synchronously.

        Type Parameters:
        T - the type of promised value
        Parameters:
        factory - the producer of the value
        Returns:
        a promise for the result of the factory
        Since:
        1.3
        See Also:
        async(Upstream), value(Object), error(Throwable)
      • flatten

        static <T> Promise<T> flatten​(Factory<? extends Promise<T>> factory)
        Creates a promise for the promise produced by the given factory.

        The given factory will be invoked every time that the value is requested. If the factory throws an exception, the promise will convey that exception.

        This can be used to effectively prepend work to another promise.

        Type Parameters:
        T - the type of promised value
        Parameters:
        factory - the producer of the promise to return
        Returns:
        a promise for the result of the factory
        Since:
        1.5
      • value

        static <T> Promise<T> value​(T t)
        Creates a promise for the given item.

        The given item will be used every time that the value is requested.

        
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String[] args) throws Exception {
             String value = ExecHarness.yieldSingle(e ->
               Promise.value("foo")
             ).getValueOrThrow();
        
             assertEquals(value, "foo");
           }
         }
         
        Type Parameters:
        T - the type of promised value
        Parameters:
        t - the promised value
        Returns:
        a promise for the given item
        See Also:
        async(Upstream), sync(Factory), error(Throwable)
      • ofNull

        static <T> Promise<T> ofNull()
        A promise for null.
        Type Parameters:
        T - the type of promised value
        Returns:
        a promise for null.
        Since:
        1.5
      • error

        static <T> Promise<T> error​(Throwable t)
        Creates a failed promise with the given error.

        The given error will be used every time that the value is requested.

        
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import static org.junit.jupiter.api.Assertions.assertSame;
        
         public class Example {
           public static void main(String[] args) throws Exception {
             Exception exception = new Exception();
             Throwable error = ExecHarness.yieldSingle(e ->
               Promise.error(exception)
             ).getThrowable();
        
             assertSame(exception, error);
           }
         }
         
        Type Parameters:
        T - the type of promised value
        Parameters:
        t - the error
        Returns:
        a failed promise
        See Also:
        async(Upstream), sync(Factory), value(Object)
      • then

        void then​(Action<? super T> then)
        Specifies what should be done with the promised object when it becomes available.

        Important: this method can only be used from a Ratpack managed compute thread. If it is called on a non Ratpack managed compute thread it will immediately throw an ExecutionException.

        Parameters:
        then - the receiver of the promised value
        Throws:
        ExecutionException - if not called on a Ratpack managed compute thread
      • connect

        void connect​(Downstream<? super T> downstream)
        A low level hook for consuming the promised value.

        It is generally preferable to use then(Action) over this method.

        Parameters:
        downstream - the downstream consumer
      • transform

        <O> Promise<O> transform​(Function<? super Upstream<? extends T>,​? extends Upstream<O>> upstreamTransformer)
        Apply a custom transform to this promise.

        This method is the basis for the standard operations of this interface, such as map(Function). The following is a non generic implementation of a map that converts the value to upper case.

        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             ExecResult<String> result = ExecHarness.yieldSingle(c ->
               Promise.value("foo")
                 .transform(up -> down ->
                   up.connect(down.<String>onSuccess(value -> {
                     try {
                       down.success(value.toUpperCase());
                     } catch (Throwable e) {
                       down.error(e);
                     }
                   }))
                 )
             );
        
             assertEquals("FOO", result.getValue());
           }
         }
         

        The “upstreamTransformer” function takes an upstream data source, and returns another upstream that wraps it. It is typical for the returned upstream to invoke the Upstream.connect(Downstream) method of the given upstream during its connect method.

        For more examples of transform implementations, please see the implementations of the methods of this interface.

        Type Parameters:
        O - the type of item emitted by the transformed upstream
        Parameters:
        upstreamTransformer - a function that returns a new upstream, typically wrapping the given upstream argument
        Returns:
        a new promise
      • onError

        default Promise<T> onError​(Predicate<? super Throwable> predicate,
                                   @NonBlocking
                                   Action<? super Throwable> errorHandler)
        Specifies the action to take if the an error occurs trying to produce the promised value, that the given predicate applies to.

        If the given action throws an exception, the original exception will be rethrown with the exception thrown by the action added to the suppressed exceptions list.

        Parameters:
        predicate - the predicate to test against the error
        errorHandler - the action to take if an error occurs
        Returns:
        A promise for the successful result
        Since:
        1.1
      • onError

        default <E extends ThrowablePromise<T> onError​(Class<E> errorType,
                                                         Action<? super E> errorHandler)
        Specifies the action to take if the an error of the given type occurs trying to produce the promised value.
        
         import ratpack.core.http.TypedData;
         import ratpack.test.embed.EmbeddedApp;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             EmbeddedApp.fromHandler(ctx ->
                 ctx.getRequest().getBody()
                   .map(TypedData::getText)
                   .map(t -> {
                     if (t.equals("1")) {
                       throw new IllegalArgumentException("validation error!");
                     } else {
                       throw new RuntimeException("some other error!");
                     }
                   })
                   .onError(IllegalArgumentException.class, e -> ctx.render("the value is invalid"))
                   .onError(e -> ctx.render("unknown error: " + e.getMessage()))
                   .then(t -> ctx.render("ok"))
             ).test(httpClient -> {
               assertEquals(httpClient.requestSpec(r -> r.getBody().text("0")).postText(), "unknown error: some other error!");
               assertEquals(httpClient.requestSpec(r -> r.getBody().text("1")).postText(), "the value is invalid");
             });
           }
         }
         

        If the given action throws an exception, the original exception will be rethrown with the exception thrown by the action added to the suppressed exceptions list.

        Type Parameters:
        E - the type of exception to handle with the given action
        Parameters:
        errorType - the type of exception to handle with the given action
        errorHandler - the action to take if an error occurs
        Returns:
        A promise for the successful result
        Since:
        1.1
      • onError

        default Promise<T> onError​(Action<? super Throwable> errorHandler)
        Specifies the action to take if an error occurs trying to produce the promised value.

        If the given action throws an exception, the original exception will be rethrown with the exception thrown by the action added to the suppressed exceptions list.

        Parameters:
        errorHandler - the action to take if an error occurs
        Returns:
        A promise for the successful result
      • map

        default <O> Promise<O> map​(Function<? super T,​? extends O> transformer)
        Transforms the promised value by applying the given function to it.
        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             ExecResult<String> result = ExecHarness.yieldSingle(c ->
                 Promise.value("foo")
                   .map(String::toUpperCase)
                   .map(s -> s + "-BAR")
             );
        
             assertEquals("FOO-BAR", result.getValue());
           }
         }
         
        Type Parameters:
        O - the type of the transformed object
        Parameters:
        transformer - the transformation to apply to the promised value
        Returns:
        a promise for the transformed value
      • mapIf

        default Promise<T> mapIf​(Predicate<? super T> predicate,
                                 Function<? super T,​? extends T> transformer)
        Transforms the promised value by applying the given function to it, if it satisfies the predicate.
        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             ExecResult<String> result = ExecHarness.yieldSingle(c ->
                 Promise.value("foo")
                   .mapIf(s -> s.contains("f"), String::toUpperCase)
                   .mapIf(s -> s.contains("f"), s -> s + "-BAR")
             );
        
             assertEquals("FOO", result.getValue());
           }
         }
         
        Parameters:
        predicate - the condition to satisfy in order to be transformed
        transformer - the transformation to apply to the promised value
        Returns:
        a promise
        Since:
        1.4
      • mapIf

        default <O> Promise<O> mapIf​(Predicate<? super T> predicate,
                                     Function<? super T,​? extends O> onTrue,
                                     Function<? super T,​? extends O> onFalse)
        Transforms the promised value by applying one of the given functions to it, depending if it satisfies the predicate.
        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             ExecResult<String> result = ExecHarness.yieldSingle(c ->
                 Promise.value("foo")
                   .mapIf(s -> s.contains("f"), String::toUpperCase, s -> s)
                   .mapIf(s -> s.contains("f"), s -> s, s -> s + "-BAR")
             );
        
             assertEquals("FOO-BAR", result.getValue());
           }
         }
         
        Type Parameters:
        O - the type of the transformed object
        Parameters:
        predicate - the condition to decide which transformation to apply
        onTrue - the transformation to apply when the predicate is true
        onFalse - the transformation to apply when the predicate is false
        Returns:
        a promise
        Since:
        1.5
      • blockingMap

        default <O> Promise<O> blockingMap​(Function<? super T,​? extends O> transformer)
        Like map(Function), but performs the transformation on a blocking thread.

        This is simply a more convenient form of using Blocking.get(Factory) and flatMap(Function).

        Type Parameters:
        O - the type of the transformed object
        Parameters:
        transformer - the transformation to apply to the promised value, on a blocking thread
        Returns:
        a promise for the transformed value
      • blockingOp

        default Promise<T> blockingOp​(Action<? super T> action)
        Executes the given action with the promise value, on a blocking thread.

        Similar to blockingMap(Function), but does not provide a new value. This can be used to do something with the value, without terminating the promise.

        Parameters:
        action - the action to to perform with the value, on a blocking thread
        Returns:
        a promise for the same value given to the action
      • next

        default Promise<T> next​(@NonBlocking
                                Action<? super T> action)
        Executes the provided, potentially asynchronous, Action with the promised value as input.

        This method can be used when needing to perform an action with the promised value, without substituting the promised value. That is, the exact same object provided to the given action will be propagated downstream.

        The given action is executed within an Operation, allowing it to perform asynchronous work.

        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
        
         import com.google.common.collect.Lists;
        
         import java.util.concurrent.TimeUnit;
         import java.util.Arrays;
         import java.util.List;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             List<String> events = Lists.newLinkedList();
             ExecHarness.runSingle(c ->
               Promise.value("foo")
                .next(v ->
                  Promise.value(v) // may be async
                    .map(String::toUpperCase)
                    .then(events::add)
                )
                .then(events::add)
             );
             assertEquals(Arrays.asList("FOO", "foo"), events);
           }
         }
         
        Parameters:
        action - the action to execute with the promised value
        Returns:
        a promise for the original value
        Since:
        1.1
        See Also:
        nextOp(Function)
      • nextOp

        default Promise<T> nextOp​(Function<? super T,​? extends Operation> function)
        Executes the operation returned by the given function.

        This method can be used when needing to perform an operation returned by another object, based on the promised value.

        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
         import ratpack.exec.Operation;
        
         import com.google.common.collect.Lists;
        
         import java.util.concurrent.TimeUnit;
         import java.util.Arrays;
         import java.util.List;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
        
           public static class CaseService {
             public Operation toUpper(String value, List<String> values) {
               return Operation.of(() -> values.add(value.toUpperCase()));
             }
           }
        
           public static void main(String... args) throws Exception {
             CaseService service = new CaseService();
             List<String> events = Lists.newLinkedList();
        
             ExecHarness.runSingle(c ->
               Promise.value("foo")
                .nextOp(v -> service.toUpper(v, events))
                .then(events::add)
             );
        
             assertEquals(Arrays.asList("FOO", "foo"), events);
           }
         }
         
        Parameters:
        function - a function that returns an operation that acts on the promised value
        Returns:
        a promise for the original value
        Since:
        1.1
        See Also:
        next(Action)
      • nextOpIf

        default Promise<T> nextOpIf​(Predicate<? super T> predicate,
                                    Function<? super T,​? extends Operation> function)
        Executes the operation returned by the given function, if it satisfies the predicate.

        This method can be used when needing to perform an operation returned by another object, based on the promised value.

        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
         import ratpack.exec.Operation;
        
         import com.google.common.collect.Lists;
        
         import java.util.concurrent.TimeUnit;
         import java.util.Arrays;
         import java.util.List;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
        
           public static class CaseService {
             public Operation toUpper(String value, List<String> values) {
               return Operation.of(() -> values.add(value.toUpperCase()));
             }
           }
        
           public static void main(String... args) throws Exception {
             CaseService service = new CaseService();
             List<String> events = Lists.newLinkedList();
        
             ExecHarness.runSingle(c ->
               Promise.value("foo")
                .nextOpIf(v -> v.startsWith("f"), v -> service.toUpper(v, events))
                .nextOpIf(v -> v.isEmpty(), v -> Operation.of(() -> events.add("empty")))
                .then(events::add)
             );
        
             assertEquals(Arrays.asList("FOO", "foo"), events);
           }
         }
         
        Parameters:
        predicate - the condition to satisfy in order to execute the operation.
        function - a function that returns an operation that acts on the promised value
        Returns:
        a promise for the original value
        Since:
        1.5
      • replace

        default <O> Promise<O> replace​(Promise<O> next)
        Replaces this promise with the provided promise for downstream subscribers.

        This is simply a more convenient form of flatMap(Function), where the given promise is returned. This method can be used when a subsequent operation on a promise isn't dependent on the actual promised value.

        If the upstream promise fails, its error will propagate downstream and the given promise will never be subscribed to.

        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           private static String value;
        
           public static void main(String... args) throws Exception {
             ExecResult<String> result = ExecHarness.yieldSingle(c ->
                 Promise.value("foo")
                   .next(v -> value = v)
                   .replace(Promise.value("bar"))
             );
        
             assertEquals("bar", result.getValue());
             assertEquals("foo", value);
           }
         }
         
        Type Parameters:
        O - the type of the value of the replacement promise
        Parameters:
        next - the promise to replace this with
        Returns:
        a promise
        Since:
        1.1
      • left

        default <O> Promise<Pair<O,​T>> left​(Promise<O> left)
        Transforms the promised value to a Pair, with the value of the given promise as the left.

        The existing promised value will become the right.

        Type Parameters:
        O - the type of the left value
        Parameters:
        left - a promise for the left value of the result pair
        Returns:
        a promise
      • left

        default <O> Promise<Pair<O,​T>> left​(Function<? super T,​? extends O> leftFunction)
        Transforms the promised value to a Pair, with the result of the given function as the left.

        The function is called with the promised value. The existing promised value will become the right.

        Type Parameters:
        O - the type of the left value
        Parameters:
        leftFunction - a function that produces the left value from the promised value
        Returns:
        a promise
        Since:
        1.4
      • flatLeft

        default <O> Promise<Pair<O,​T>> flatLeft​(Function<? super T,​? extends Promise<O>> leftFunction)
        Transforms the promised value to a Pair, with the value of the result of the given function as the left.

        The function is called with the promised value. The existing promised value will become the right.

        Type Parameters:
        O - the type of the left value
        Parameters:
        leftFunction - a function that produces a promise for the left value from the promised value
        Returns:
        a promise
        Since:
        1.4
      • right

        default <O> Promise<Pair<T,​O>> right​(Promise<O> right)
        Transforms the promised value to a Pair, with the value of the given promise as the right.

        The existing promised value will become the left.

        Type Parameters:
        O - the type of the right value
        Parameters:
        right - a promise for the right value of the result pair
        Returns:
        a promise
      • right

        default <O> Promise<Pair<T,​O>> right​(Function<? super T,​? extends O> rightFunction)
        Transforms the promised value to a Pair, with the result of the given function as the right.

        The function is called with the promised value. The existing promised value will become the left.

        Type Parameters:
        O - the type of the left value
        Parameters:
        rightFunction - a function that produces the right value from the promised value
        Returns:
        a promise
        Since:
        1.4
      • flatRight

        default <O> Promise<Pair<T,​O>> flatRight​(Function<? super T,​? extends Promise<O>> rightFunction)
        Transforms the promised value to a Pair, with the value of the result of the given function as the right.

        The function is called with the promised value. The existing promised value will become the left.

        Type Parameters:
        O - the type of the left value
        Parameters:
        rightFunction - a function that produces a promise for the right value from the promised value
        Returns:
        a promise
        Since:
        1.4
      • operation

        default Operation operation()
        Converts this promise to an operation, by effectively discarding the result.
        Returns:
        an operation
      • operation

        default Operation operation​(@NonBlocking
                                    Action<? super T> action)
        Converts this promise to an operation which is effectively action.
        Parameters:
        action - an operation on the promised value
        Returns:
        an operation representing action
      • flatOp

        default Operation flatOp​(Function<? super T,​? extends Operation> function)
        Converts this promise to an operation, which is the return of function.
        Parameters:
        function - a function that returns an operation for the promised value
        Returns:
        effectively the return of function
        Since:
        1.6
      • mapError

        default Promise<T> mapError​(Function<? super Throwable,​? extends T> transformer)
        Transforms the promise failure (potentially into a value) by applying the given function to it.

        If the function returns a value, the promise will now be considered successful.

        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             ExecResult<String> result = ExecHarness.yieldSingle(c ->
                 Promise.<String>error(new Exception("!"))
                   .mapError(e -> "value")
             );
        
             assertEquals("value", result.getValue());
           }
         }
         

        If the function throws an exception, that exception will now represent the promise failure.

        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             ExecResult<String> result = ExecHarness.yieldSingle(c ->
                 Promise.<String>error(new Exception("!"))
                   .mapError(e -> { throw new RuntimeException("mapped", e); })
             );
        
             assertEquals("mapped", result.getThrowable().getMessage());
           }
         }
         

        The function will not be called if the promise is successful.

        Parameters:
        transformer - the transformation to apply to the promise failure
        Returns:
        a promise
      • mapError

        default <E extends ThrowablePromise<T> mapError​(Class<E> type,
                                                          Function<? super E,​? extends T> function)
        Transforms a failure of the given type (potentially into a value) by applying the given function to it.

        This method is similar to mapError(Function), except that it will only apply if the error is of the given type. If the error is not of the given type, it will not be transformed and will propagate as normal.

        Parameters:
        function - the transformation to apply to the promise failure
        Returns:
        a promise
        Since:
        1.3
      • mapError

        default Promise<T> mapError​(Predicate<? super Throwable> predicate,
                                    Function<? super Throwable,​? extends T> function)
        Transforms a failure of the given type (potentially into a value) by applying the given function to it.

        This method is similar to mapError(Function), except that it will only apply depending if it satisfies the predicate. If the error is not of the given type, it will not be transformed and will propagate as normal.

        Parameters:
        predicate - the predicate to test against the error
        function - the transformation to apply to the promise failure
        Returns:
        a promise
        Since:
        1.6.0
      • flatMapError

        default Promise<T> flatMapError​(Function<? super Throwable,​? extends Promise<T>> function)
        Transforms a failure of the given type (potentially into a value) by applying the given function to it.

        This method is similar to mapError(Function), except that it allows async transformation.

        Parameters:
        function - the transformation to apply to the promise failure
        Returns:
        a promise
        Since:
        1.3
      • flatMapError

        default <E extends ThrowablePromise<T> flatMapError​(Class<E> type,
                                                              Function<? super E,​? extends Promise<T>> function)
        Transforms a failure of the given type (potentially into a value) by applying the given function to it.

        This method is similar to mapError(Class, Function), except that it allows async transformation.

        Parameters:
        function - the transformation to apply to the promise failure
        Returns:
        a promise
        Since:
        1.3
      • flatMapError

        default Promise<T> flatMapError​(Predicate<? super Throwable> predicate,
                                        Function<? super Throwable,​? extends Promise<T>> function)
        Transforms a failure of the given type (potentially into a value) by applying the given function to it.

        This method is similar to mapError(Predicate, Function), except that it allows async transformation.

        Parameters:
        predicate - the predicate to test against the error
        function - the transformation to apply to the promise failure
        Returns:
        a promise
        Since:
        1.6.0
      • apply

        default <O> Promise<O> apply​(Function<? super Promise<T>,​? extends Promise<O>> function)
        Applies the custom operation function to this promise.

        This method can be used to apply custom operations without breaking the “code flow”. It works particularly well with method references.

        
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             Integer value = ExecHarness.yieldSingle(e ->
                 Promise.value(1)
                   .apply(Example::dubble)
                   .apply(Example::triple)
             ).getValue();
        
             assertEquals(Integer.valueOf(6), value);
           }
        
           public static Promise<Integer> dubble(Promise<Integer> input) {
             return input.map(i -> i * 2);
           }
        
           public static Promise<Integer> triple(Promise<Integer> input) {
             return input.map(i -> i * 3);
           }
         }
         

        If the apply function throws an exception, the returned promise will fail.

        
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             Throwable error = ExecHarness.yieldSingle(e ->
                 Promise.value(1)
                   .apply(Example::explode)
             ).getThrowable();
        
             assertEquals("bang!", error.getMessage());
           }
        
           public static Promise<Integer> explode(Promise<Integer> input) throws Exception {
             throw new Exception("bang!");
           }
         }
         

        If the promise having the operation applied to fails, the operation will not be applied.

        
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             Throwable error = ExecHarness.yieldSingle(e ->
                 Promise.<Integer>error(new Exception("bang!"))
                   .apply(Example::dubble)
             ).getThrowable();
        
             assertEquals("bang!", error.getMessage());
           }
        
           public static Promise<Integer> dubble(Promise<Integer> input) {
             return input.map(i -> i * 2);
           }
         }
         
        Type Parameters:
        O - the type of promised object after the operation
        Parameters:
        function - the operation implementation
        Returns:
        the transformed promise
      • to

        default <O> O to​(Function<? super Promise<T>,​? extends O> function)
                  throws Exception
        Applies the given function to this and returns the result.

        This method can be useful when needing to convert a promise to another type as it facilitates doing so without breaking the “code flow”. For example, this can be used when integrating with RxJava.

        
         import ratpack.rx2.RxRatpack;
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import java.util.Arrays;
         import java.util.LinkedList;
         import java.util.List;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           private static final List<String> LOG = new LinkedList<>();
        
           public static void main(String... args) throws Exception {
             ExecHarness.runSingle(e ->
                 Promise.value("foo")
                   .to(RxRatpack::single)
                   .doOnSuccess(i -> LOG.add("doOnNext"))
                   .subscribe(i -> LOG.add(i))
             );
        
             assertEquals(Arrays.asList("doOnNext", "foo"), LOG);
           }
         }
         

        The given function is executed immediately.

        This method should only be used when converting a promise to another type. See apply(Function) for applying custom promise operators.

        Type Parameters:
        O - the type the promise will be converted to
        Parameters:
        function - the promise conversion function
        Returns:
        the output of the given function
        Throws:
        Exception - any thrown by the given function
      • flatMap

        default <O> Promise<O> flatMap​(Function<? super T,​? extends Promise<O>> transformer)
        Transforms the promised value by applying the given function to it that returns a promise for the transformed value.

        This is useful when the transformation involves an asynchronous operation.

        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
         import ratpack.exec.Blocking;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String[] args) throws Exception {
             ExecResult<String> result = ExecHarness.yieldSingle(c ->
                 Promise.value("foo")
                   .flatMap(s -> Blocking.get(s::toUpperCase))
                   .map(s -> s + "-BAR")
             );
        
             assertEquals("FOO-BAR", result.getValue());
           }
         }
         

        Type Parameters:
        O - the type of the transformed object
        Parameters:
        transformer - the transformation to apply to the promised value
        Returns:
        a promise for the transformed value
      • flatMapIf

        default Promise<T> flatMapIf​(Predicate<? super T> predicate,
                                     Function<? super T,​? extends Promise<T>> transformer)
        Transforms the promised value by applying the given function to it that returns a promise for the transformed value, if it satisfies the predicate.
        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             ExecResult<String> result = ExecHarness.yieldSingle(c ->
                 Promise.value("foo")
                   .flatMapIf(s -> s.contains("f"), s -> Promise.value(s.toUpperCase()))
                   .flatMapIf(s -> s.contains("f"), s -> Promise.value(s + "-BAR"))
             );
        
             assertEquals("FOO", result.getValue());
           }
         }
         
        Parameters:
        predicate - the condition to satisfy in order to be transformed
        transformer - the transformation to apply to the promised value
        Returns:
        a promise
        Since:
        1.4
      • flatMapIf

        default <O> Promise<O> flatMapIf​(Predicate<? super T> predicate,
                                         Function<? super T,​? extends Promise<O>> onTrue,
                                         Function<? super T,​? extends Promise<O>> onFalse)
        Transforms the promised value by applying one of the given functions to it that returns a promise for the transformed value, depending if it satisfies the predicate.
        
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             ExecResult<String> result = ExecHarness.yieldSingle(c ->
                 Promise.value("foo")
                   .flatMapIf(s -> s.contains("f"), s -> Promise.value(s.toUpperCase()), s -> Promise.value(s))
                   .flatMapIf(s -> s.contains("f"), s -> Promise.value(s), s -> Promise.value(s + "-BAR"))
             );
        
             assertEquals("FOO-BAR", result.getValue());
           }
         }
         
        Parameters:
        predicate - the condition to decide which transformation to apply
        onTrue - the transformation to apply to the promised value when the predicate is true
        onFalse - the transformation to apply to the promised value when the predicate is false
        Returns:
        a promise
        Since:
        1.5
      • route

        default Promise<T> route​(Predicate<? super T> predicate,
                                 Action<? super T> action)
        Allows the promised value to be handled specially if it meets the given predicate, instead of being handled by the promise subscriber.

        This is typically used for validating values, centrally.

        
         import com.google.common.collect.Lists;
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
        
         import java.util.List;
        
         import static org.junit.jupiter.api.Assertions.*;
        
         public class Example {
           public static ExecResult<Integer> yield(int i, List<Integer> collector) throws Exception {
             return ExecHarness.yieldSingle(c ->
                 Promise.value(i)
                   .route(v -> v > 5, collector::add)
             );
           }
        
           public static void main(String... args) throws Exception {
             List<Integer> routed = Lists.newLinkedList();
        
             ExecResult<Integer> result1 = yield(1, routed);
             assertEquals(Integer.valueOf(1), result1.getValue());
             assertFalse(result1.isComplete()); // false because promise returned a value before the execution completed
             assertTrue(routed.isEmpty());
        
             ExecResult<Integer> result10 = yield(10, routed);
             assertNull(result10.getValue());
             assertTrue(result10.isComplete()); // true because the execution completed before the promised value was returned (i.e. it was routed)
             assertTrue(routed.contains(10));
           }
         }
         

        Be careful about using this where the eventual promise subscriber is unlikely to know that the promise will routed as it can be surprising when neither the promised value nor an error appears.

        It can be useful at the handler layer to provide common validation.

        
         import ratpack.exec.Promise;
         import ratpack.core.handling.Context;
         import ratpack.test.embed.EmbeddedApp;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static Promise<Integer> getAge(Context ctx) {
             return Promise.value(10)
               .route(
                 i -> i < 21,
                 i -> ctx.render(i + " is too young to be here!")
               );
           }
        
           public static void main(String... args) throws Exception {
             EmbeddedApp.fromHandler(ctx ->
                 getAge(ctx).then(age -> ctx.render("welcome!"))
             ).test(httpClient -> {
               assertEquals("10 is too young to be here!", httpClient.getText());
             });
           }
         }
         

        If the routed-to action throws an exception, it will be forwarded down the promise chain.

        Parameters:
        predicate - the condition under which the value should be routed
        action - the terminal action for the value
        Returns:
        a routed promise
      • onNull

        default Promise<T> onNull​(Block action)
        A convenience shorthand for routing null values.

        If the promised value is null, the given action will be called.

        Parameters:
        action - the action to route to if the promised value is null
        Returns:
        a routed promise
      • cache

        default Promise<T> cache()
        Caches the promised value (or error) and returns it to all subscribers.

        This method is equivalent to using cacheResultIf(Predicate) with a predicate that always returns true.

        
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import java.util.concurrent.atomic.AtomicLong;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             ExecHarness.runSingle(c -> {
               AtomicLong counter = new AtomicLong();
               Promise<Long> uncached = Promise.async(f -> f.success(counter.getAndIncrement()));
        
               uncached.then(i -> assertEquals(0l, i.longValue()));
               uncached.then(i -> assertEquals(1l, i.longValue()));
               uncached.then(i -> assertEquals(2l, i.longValue()));
        
               Promise<Long> cached = uncached.cache();
        
               cached.then(i -> assertEquals(3l, i.longValue()));
               cached.then(i -> assertEquals(3l, i.longValue()));
        
               uncached.then(i -> assertEquals(4l, i.longValue()));
               cached.then(i -> assertEquals(3l, i.longValue()));
             });
           }
         }
         

        If the cached promise fails, the same exception will be returned every time.

        
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import static org.junit.jupiter.api.Assertions.assertTrue;
        
         public class Example {
           public static void main(String... args) throws Exception {
             ExecHarness.runSingle(c -> {
               Throwable error = new Exception("bang!");
               Promise<Object> cached = Promise.error(error).cache();
               cached.onError(t -> assertTrue(t == error)).then(i -> assertTrue(false, "not called"));
               cached.onError(t -> assertTrue(t == error)).then(i -> assertTrue(false, "not called"));
               cached.onError(t -> assertTrue(t == error)).then(i -> assertTrue(false, "not called"));
             });
           }
         }
         
        Returns:
        a caching promise
        See Also:
        cacheIf(Predicate), cacheResultIf(Predicate), cacheResultFor(Function)
      • cacheIf

        default Promise<T> cacheIf​(Predicate<? super T> shouldCache)
        Caches the promise value and provides it to all future subscribers, if it satisfies the predicate.

        This method is equivalent to using cacheResultIf(Predicate) with a predicate that requires a successful result and for the value to satisfy the predicate given to this method.

        Non success results will not be cached.

        Parameters:
        shouldCache - the test for whether a successful result is cacheable
        Returns:
        a caching promise
        Since:
        1.4
        See Also:
        cacheResultIf(Predicate), cacheResultFor(Function)
      • cacheResultIf

        default Promise<T> cacheResultIf​(Predicate<? super ExecResult<T>> shouldCache)
        Caches the promise result eternally and provide it to all future subscribers, if it satisfies the predicate.
        
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import java.util.ArrayList;
         import java.util.List;
         import java.util.concurrent.atomic.AtomicInteger;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
        
           public static void main(String... args) throws Exception {
             List<ExecResult<Integer>> results = new ArrayList<>();
             AtomicInteger counter = new AtomicInteger();
             Promise<Integer> promise = Promise.sync(() -> {
               int i = counter.getAndIncrement();
               if (i < 2) {
                 return i;
               } else if (i == 2) {
                 throw new Exception(Integer.toString(i));
               } else if (i == 3) {
                 throw new RuntimeException(Integer.toString(i));
               } else {
                 throw new IllegalStateException(Integer.toString(i));
               }
             });
        
             Promise<Integer> cachedPromise = promise.cacheResultIf(r ->
               (r.isError() && r.getThrowable().getClass() == RuntimeException.class)
                 || (r.isSuccess() && r.getValue() > 10)
             );
        
             ExecHarness.runSingle(e -> {
               for (int i = 0; i < 6; i++) {
                 cachedPromise.result(results::add);
               }
             });
        
             assertEquals(results.get(0).getValueOrThrow(), Integer.valueOf(0));
             assertEquals(results.get(1).getValueOrThrow(), Integer.valueOf(1));
             assertEquals(results.get(2).getThrowable().getClass(), Exception.class);
             assertEquals(results.get(3).getThrowable().getClass(), RuntimeException.class);
        
             // value is now cached
             assertEquals(results.get(4).getThrowable().getClass(), RuntimeException.class);
             assertEquals(results.get(5).getThrowable().getClass(), RuntimeException.class);
           }
         }
         

        Note, the cached value never expires. If you wish to cache for a certain amount of time, use cacheResultFor(Function).

        Parameters:
        shouldCache - the test for whether a result is cacheable
        Returns:
        a caching promise
        Since:
        1.4
        See Also:
        cache(), cacheIf(Predicate), cacheResultFor(Function)
      • cacheResultFor

        default Promise<T> cacheResultFor​(Function<? super ExecResult<T>,​Duration> cacheFor)
        Caches the promise result for a calculated amount of time.

        A cached promise is fully threadsafe and and can be subscribed to concurrently. While there is no valid cached value, yielding the upstream value is serialised. That is, one value is requested at a time regardless of concurrent subscription.

        As the result is received, it is given to the ttlFunc which determines how long to cache it for. A Duration.ZERO duration indicates that the value should not be cached. Any Duration.isNegative() duration indicates that the value should be cached eternally. Any other duration indicates how long to cache the result for.

        If the promise is subscribed to again after the cached value has expired, the process repeats.

        As such promises tend to be held and reused, it is sometimes necessary to consider garbage collection implications. A caching promise (like all multi-use promises) must retain all of its upstream functions/objects. Care should be taken to ensure that this does not cause long lived references to objects that should be collected.

        It is common to use cached promises in conjunction with a cache implementation such as Google Guava or Caffeine.

        
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import java.util.ArrayList;
         import java.util.List;
         import java.time.Duration;
         import java.util.concurrent.atomic.AtomicInteger;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
        
           public static void main(String... args) throws Exception {
             List<Integer> results = new ArrayList<>();
             AtomicInteger counter = new AtomicInteger();
             Promise<Integer> promise = Promise.sync(counter::getAndIncrement)
               .cacheResultFor(
                 i -> i.isSuccess() && i.getValue() > 1
                 ? Duration.ofSeconds(1)
                 : Duration.ZERO
               );
        
             for (int i = 0; i < 4; ++i) {
               ExecHarness.runSingle(e -> promise.then(results::add));
             }
        
             // let the cache entry expire
             Thread.sleep(1500);
        
             for (int i = 0; i < 2; ++i) {
               ExecHarness.runSingle(e -> promise.then(results::add));
             }
        
             assertEquals(results.get(0), Integer.valueOf(0));
             assertEquals(results.get(1), Integer.valueOf(1));
             assertEquals(results.get(2), Integer.valueOf(2));
             assertEquals(results.get(3), Integer.valueOf(2));
        
             // cache entry has expired
        
             assertEquals(results.get(4), Integer.valueOf(3));
             assertEquals(results.get(5), Integer.valueOf(3));
           }
         }
         
        Parameters:
        cacheFor - a function that determines how long to cache the given result for
        Returns:
        a caching promise
        Since:
        1.5
        See Also:
        cache(), cacheIf(Predicate), cacheResultIf(Predicate)
      • defer

        default Promise<T> defer​(Action<? super Runnable> releaser)
        Defers the subscription of this promise until later.

        When the returned promise is subscribed to, the given releaser action will be invoked. The execution of this promise is deferred until the runnable given to the releaser is run.

        It is important to note that this defers the subscription of the promise, not the delivery of the value.

        It is generally more convenient to use throttled(Throttle) or onYield(Runnable) than this operation.

        Parameters:
        releaser - the action that will initiate the execution some time later
        Returns:
        a deferred promise
      • defer

        default Promise<T> defer​(Duration duration)
        Defers the subscription of this promise for the given duration.

        This operation is roughly the promise based analog of Execution.sleep(Duration, Block).

        The given duration must be non-negative.

        Parameters:
        duration - the amount of time to defer for
        Returns:
        a deferred promise
        Since:
        1.5
        See Also:
        defer(Action)
      • onYield

        default Promise<T> onYield​(Runnable onYield)
        Registers a listener that is invoked when this promise is initiated.
        
         import com.google.common.collect.Lists;
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.Promise;
        
         import java.util.Arrays;
         import java.util.List;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             List<String> events = Lists.newLinkedList();
             ExecHarness.runSingle(c ->
                 Promise.<String>sync(() -> {
                   events.add("promise");
                   return "foo";
                 })
                   .onYield(() -> events.add("onYield"))
                   .then(v -> events.add("then"))
             );
             assertEquals(Arrays.asList("onYield", "promise", "then"), events);
           }
         }
         
        Parameters:
        onYield - the action to take when the promise is initiated
        Returns:
        effectively, this promise
      • wiretap

        default Promise<T> wiretap​(Action<? super Result<T>> listener)
        Registers a listener for the promise outcome.
        
         import com.google.common.collect.Lists;
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.Promise;
        
         import java.util.Arrays;
         import java.util.List;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           public static void main(String... args) throws Exception {
             List<String> events = Lists.newLinkedList();
             ExecHarness.runSingle(c ->
                 Promise.<String>sync(() -> {
                   events.add("promise");
                   return "foo";
                 })
                   .wiretap(r -> events.add("wiretap: " + r.getValue()))
                   .then(v -> events.add("then"))
             );
        
             assertEquals(Arrays.asList("promise", "wiretap: foo", "then"), events);
           }
         }
         
        Parameters:
        listener - the result listener
        Returns:
        effectively, this promise
      • throttled

        default Promise<T> throttled​(Throttle throttle)
        Throttles this promise, using the given throttle.

        Throttling can be used to limit concurrency. Typically to limit concurrent use of an external resource, such as a HTTP API.

        Note that the Throttle instance given defines the actual throttling semantics.

        
         import ratpack.exec.Throttle;
         import ratpack.exec.Promise;
         import ratpack.exec.Execution;
         import ratpack.test.exec.ExecHarness;
         import ratpack.exec.ExecResult;
        
         import java.util.concurrent.atomic.AtomicInteger;
        
         import static org.junit.jupiter.api.Assertions.assertTrue;
        
         public class Example {
           public static void main(String... args) throws Exception {
             int numJobs = 1000;
             int maxAtOnce = 10;
        
             ExecResult<Integer> result = ExecHarness.yieldSingle(exec -> {
               AtomicInteger maxConcurrent = new AtomicInteger();
               AtomicInteger active = new AtomicInteger();
               AtomicInteger done = new AtomicInteger();
        
               Throttle throttle = Throttle.ofSize(maxAtOnce);
        
               // Launch numJobs forked executions, and return the maximum number that were executing at any given time
               return Promise.async(downstream -> {
                 for (int i = 0; i < numJobs; i++) {
                   Execution.fork().start(forkedExec ->
                     Promise.sync(() -> {
                       int activeNow = active.incrementAndGet();
                       int maxConcurrentVal = maxConcurrent.updateAndGet(m -> Math.max(m, activeNow));
                       active.decrementAndGet();
                       return maxConcurrentVal;
                     })
                     .throttled(throttle) // limit concurrency
                     .then(max -> {
                       if (done.incrementAndGet() == numJobs) {
                         downstream.success(max);
                       }
                     })
                   );
                 }
               });
             });
        
             assertTrue(result.getValue() <= maxAtOnce);
           }
         }
         
        Parameters:
        throttle - the particular throttle to use to throttle the operation
        Returns:
        the throttled promise
      • close

        default Promise<T> close​(AutoCloseable closeable)
        Closes the given closeable when the value or error propagates to this point.

        This can be used to simulate a try/finally synchronous construct. It is typically used to close some resource after an asynchronous operation.

        
         import ratpack.exec.Promise;
         import ratpack.test.exec.ExecHarness;
        
         import static org.junit.jupiter.api.Assertions.assertTrue;
        
         public class Example {
           static class MyResource implements AutoCloseable {
             final boolean inError;
             boolean closed;
        
             public MyResource(boolean inError) {
               this.inError = inError;
             }
        
             @Override
             public void close() {
               closed = true;
             }
           }
        
           static Promise<String> resourceUsingMethod(MyResource resource) {
             return Promise.sync(() -> {
               if (resource.inError) {
                 throw new Exception("error!");
               } else {
                 return "ok!";
               }
             });
           }
        
           public static void main(String[] args) throws Exception {
             ExecHarness.runSingle(e -> {
               MyResource myResource = new MyResource(false);
               resourceUsingMethod(myResource)
                 .close(myResource)
                 .then(value -> assertTrue(myResource.closed));
             });
        
             ExecHarness.runSingle(e -> {
               MyResource myResource = new MyResource(true);
               resourceUsingMethod(myResource)
                 .close(myResource)
                 .onError(error -> assertTrue(myResource.closed))
                 .then(value -> {
                   throw new UnsupportedOperationException("should not reach here!");
                 });
             });
        
           }
         }
         

        The general pattern is to open the resource, and then pass it to some method/closure that works with it and returns a promise. This method is then called on the returned promise to cleanup the resource.

        Parameters:
        closeable - the closeable to close
        Returns:
        a promise
        Since:
        1.3
        See Also:
        close(Operation)
      • close

        default Promise<T> close​(Operation closer)
        Like close(AutoCloseable), but allows async close operations.
        Parameters:
        closer - the close operation.
        Returns:
        a promise
        Since:
        1.5
      • time

        default Promise<T> time​(Action<? super Duration> action)
        Emits the time taken from when the promise is subscribed to to when the result is available.

        The given action is called regardless of whether the promise is successful or not.

        If the promise fails and this method throws an exception, the original exception will propagate with the thrown exception suppressed. If the promise succeeds and this method throws an exception, the thrown exception will propagate.

        Parameters:
        action - a callback for the time
        Returns:
        effectively this
        Since:
        1.3
        See Also:
        timeResult(BiAction)
      • timeResult

        default Promise<T> timeResult​(BiAction<? super ExecResult<T>,​? super Duration> action)
        Emits the time taken from when the promise is subscribed to to when the result is available.

        The given action is called regardless of whether the promise is successful or not.

        If the promise fails and this method throws an exception, the original exception will propagate with the thrown exception suppressed. If the promise succeeds and this method throws an exception, the thrown exception will propagate.

        Parameters:
        action - a callback for the time
        Returns:
        effectively this
        Since:
        1.5
        See Also:
        time(Action)
      • around

        default <B,​A> Promise<A> around​(Factory<? extends B> before,
                                              BiFunction<? super B,​? super ExecResult<T>,​? extends ExecResult<A>> after)
        Facilitates capturing a value before the the promise is subscribed and using it to later augment the result.

        The before factory is invoked as the promise is subscribed. As the promise result becomes available, it and the result are given to the after function. The return value of the after function forms the basis of the promise returned from this method.

        Type Parameters:
        B - the before value type
        A - the after value type
        Parameters:
        before - the before value supplier
        after - the after function
        Returns:
        a promise
        Since:
        1.5
      • fork

        default Promise<T> fork​(Action<? super ExecSpec> execSpec)
                         throws Exception
        Forks a new execution and subscribes to this promise, returning a promise for its value.

        The new execution is created and started immediately by this method, effectively subscribing to the promise immediately. The returned promise provides the value when the execution completes.

        This method can be used for simple of processing. It is often combined with the left(Promise) or right(Promise).

        
         import ratpack.exec.Blocking;
         import ratpack.exec.Promise;
         import ratpack.func.Pair;
         import ratpack.test.exec.ExecHarness;
        
         import java.util.concurrent.CyclicBarrier;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
        
           public static void main(String... args) throws Exception {
             CyclicBarrier barrier = new CyclicBarrier(2);
        
             Pair<Integer, String> result = ExecHarness.yieldSingle(r -> {
               Promise<Integer> p1 = Blocking.get(() -> {
                 barrier.await();
                 return 1;
               });
               Promise<String> p2 = Blocking.get(() -> {
                 barrier.await();
                 return "2";
               });
        
               return p1.right(p2.fork());
             }).getValueOrThrow();
        
             assertEquals(result, Pair.of(1, "2"));
           }
        
         }
         

        Warning: be mindful of error handling for forked promises. If the forked promise is never subscribed to, its failure may go unnoticed. In scenarios, where it cannot be guaranteed that the forked promise will be subscribed to or that subscribers would satisfactorily deal with error conditions, consider listening for errors by using wiretap(Action) before fork() and logging the error or similar.

        Parameters:
        execSpec - configuration for the forked execution
        Returns:
        a promise
        Throws:
        Exception - any thrown by execSpec
        Since:
        1.4
      • fork

        default Promise<T> fork()
        Forks a new execution and subscribes to this promise, returning a promise for its value.

        This method delegates to fork(Action) with Action.noop().

        Returns:
        a promise
        Since:
        1.4
        See Also:
        fork(Action)
      • retry

        default Promise<T> retry​(RetryPolicy retryPolicy,
                                 BiAction<? super Integer,​? super Throwable> onError)
        Causes this yielding the promised value to be retried on error, under the rules of provided retryPolicy.

        The given function is invoked for each failure, with the sequence number of the failure as the first argument and the failure exception as the second. This may be used to log or collect exceptions. If all errors are to be ignored, use BiAction.noop().

        Any exception thrown by the function – possibly the exception it receives as an argument – will be propagated to the subscriber, yielding a failure. This can be used to selectively retry on certain failures, but immediately fail on others.

        If the promise exhausts the retryPolicy, the given function will not be invoked and the most recent exception will propagate.

        
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
         import ratpack.exec.util.retry.AttemptRetryPolicy;
         import ratpack.exec.util.retry.RetryPolicy;
         import ratpack.exec.util.retry.FixedDelay;
         import ratpack.test.exec.ExecHarness;
        
         import java.time.Duration;
         import java.util.Arrays;
         import java.util.LinkedList;
         import java.util.List;
         import java.util.concurrent.atomic.AtomicInteger;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           private static final List<String> LOG = new LinkedList<>();
        
           public static void main(String... args) throws Exception {
             AtomicInteger source = new AtomicInteger();
        
             RetryPolicy retryPolicy = AttemptRetryPolicy.of(b -> b
               .delay(FixedDelay.of(Duration.ofMillis(500)))
               .maxAttempts(3));
        
             ExecResult<Integer> result = ExecHarness.yieldSingle(exec ->
               Promise.sync(source::incrementAndGet)
                 .mapIf(i -> i < 3, i -> { throw new IllegalStateException(); })
                 .retry(retryPolicy, (i, t) -> LOG.add("retry attempt: " + i))
             );
        
             assertEquals(Integer.valueOf(3), result.getValue());
             assertEquals(Arrays.asList("retry attempt: 1", "retry attempt: 2"), LOG);
           }
         }
         
        Parameters:
        retryPolicy - policy to govern this retry behaviour
        onError - the error handler
        Returns:
        a promise with a retry error handler
        Since:
        1.7
      • retryIf

        default Promise<T> retryIf​(Predicate<? super Throwable> predicate,
                                   RetryPolicy retryPolicy,
                                   BiAction<? super Integer,​? super Throwable> onError)
        Causes this yielding the promised value to be retried on error, under the rules of provided retryPolicy, and if the given Predicate matches the error thrown.

        The given function is invoked for each failure, with the sequence number of the failure as the first argument and the failure exception as the second. This may be used to log or collect exceptions. If all errors are to be ignored, use BiAction.noop().

        Any exception thrown by the function – possibly the exception it receives as an argument – will be propagated to the subscriber, yielding a failure. This can be used to selectively retry on certain failures, but immediately fail on others.

        If the promise exhausts the retryPolicy, the given function will not be invoked and the most recent exception will propagate.

        
         import ratpack.exec.ExecResult;
         import ratpack.exec.Promise;
         import ratpack.exec.util.retry.AttemptRetryPolicy;
         import ratpack.exec.util.retry.RetryPolicy;
         import ratpack.exec.util.retry.FixedDelay;
         import ratpack.test.exec.ExecHarness;
        
         import java.time.Duration;
         import java.util.Arrays;
         import java.util.LinkedList;
         import java.util.List;
         import java.util.concurrent.atomic.AtomicInteger;
        
         import static org.junit.jupiter.api.Assertions.assertEquals;
        
         public class Example {
           private static final List<String> LOG = new LinkedList<>();
        
           public static void main(String... args) throws Exception {
             AtomicInteger source = new AtomicInteger();
        
             RetryPolicy retryPolicy = AttemptRetryPolicy.of(b -> b
               .delay(FixedDelay.of(Duration.ofMillis(500)))
               .maxAttempts(3));
        
             ExecResult<Integer> result = ExecHarness.yieldSingle(exec ->
               Promise.sync(source::incrementAndGet)
                 .mapIf(i -> i < 3, i -> { throw new IllegalStateException(); })
                 .retryIf(t -> t instanceof IllegalStateException, retryPolicy, (i, t) -> LOG.add("retry attempt: " + i))
             );
        
             assertEquals(Integer.valueOf(3), result.getValue());
             assertEquals(Arrays.asList("retry attempt: 1", "retry attempt: 2"), LOG);
           }
         }
         
        Parameters:
        predicate - the predicate against which thrown errors are matched. If the predicate succeeds, the retry is allowed to execute
        retryPolicy - policy to govern this retry behaviour
        onError - the error handler
        Returns:
        a promise with a retry error handler
        Since:
        1.8