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