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