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