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