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