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 }