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