View Javadoc
1   package io.atlassian.fugue.extensions.step;
2   
3   import io.atlassian.fugue.Try;
4   
5   import java.util.function.BiFunction;
6   import java.util.function.BiPredicate;
7   import java.util.function.Function;
8   import java.util.function.Supplier;
9   
10  /**
11   * The second step of the {@link Try} type.
12   * <p>
13   * This class is not intended to be contructed manually, and should only be used
14   * as part of a {@link Steps} chain, started by {@link Steps#begin(Try)}
15   *
16   * @param <A> The type of the first defined value
17   * @param <B> The type of the second defined value
18   * @see Steps for usage examples
19   * @see Try
20   * @since 4.7.0
21   */
22  public final class TryStep2<A, B> {
23  
24    private final Try<A> try1;
25    private final Try<B> try2;
26  
27    TryStep2(Try<A> try1, Try<B> try2) {
28      this.try1 = try1;
29      this.try2 = try2;
30    }
31  
32    /**
33     * Apply the provided function with the previous Step results.
34     * <p>
35     * Internally this will perform a {@link Try#flatMap(Function)} and the result
36     * will become the next step value.
37     *
38     * @param functor The functor to be applied as a flatMap with the previous
39     * steps
40     * @param <C> The type of the next step result
41     * @return The next step class
42     */
43    public <C> TryStep3<A, B, C> then(BiFunction<? super A, ? super B, Try<C>> functor) {
44      Try<C> try3 = try1.flatMap(value1 -> try2.flatMap(value2 -> functor.apply(value1, value2)));
45      return new TryStep3<>(try1, try2, try3);
46    }
47  
48    /**
49     * Apply the provided supplier with the previous Step results.
50     * <p>
51     * Internally this will perform a {@link Try#flatMap(Function)} and the
52     * supplier will become the next step value.
53     * <p>
54     * This is different to {@link #then(BiFunction)} in that the previous step
55     * results are not provided for the new step evaluation.
56     *
57     * @param supplier The supplier to provide the result of the flatMap with the
58     * previous step.
59     * @param <C> The type of the next step result
60     * @return The next step class
61     */
62    public <C> TryStep3<A, B, C> then(Supplier<Try<C>> supplier) {
63      Try<C> Try = try1.flatMap(value1 -> try2.flatMap(value2 -> supplier.get()));
64      return new TryStep3<>(try1, try2, Try);
65    }
66  
67    /**
68     * Apply the provided predicate with the previous step results.
69     * <p>
70     * If the predicate is not satisfied then the unsatisfiedSupplier is used to
71     * populate the failure value that will prevent any further steps evaluation.
72     *
73     * @param predicate The check that must be satisfied by contained values
74     * @param unsatisfiedSupplier Provide the value to populate the failure if not
75     * satisfied
76     * @return This step class with either the same last step value, or changed to
77     * a failure
78     */
79    public TryStep2<A, B> filter(BiPredicate<? super A, ? super B> predicate, Supplier<Exception> unsatisfiedSupplier) {
80      Try<B> filterTry2 = try1.flatMap(value1 -> try2.filterOrElse(value2 -> predicate.test(value1, value2), unsatisfiedSupplier));
81      return new TryStep2<>(try1, filterTry2);
82    }
83  
84    /**
85     * Terminating step expression, that will provide the previous steps to this
86     * function and return the result as a <code>Success</code>
87     *
88     * @param functor The yield function to map on previous values
89     * @param <Z> The type for the returned result
90     * @return A Try containing this result as success or failure
91     */
92    public <Z> Try<Z> yield(BiFunction<? super A, ? super B, Z> functor) {
93      return try1.flatMap(value1 -> try2.map(value2 -> functor.apply(value1, value2)));
94    }
95  
96  }