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