1 package io.atlassian.fugue.extensions.step;
2
3 import io.atlassian.fugue.extensions.functions.Function3;
4 import io.atlassian.fugue.extensions.functions.Predicate3;
5
6 import java.util.Optional;
7 import java.util.function.Function;
8 import java.util.function.Supplier;
9
10 /**
11 * The third step of the {@link Optional} 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(Optional)}
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 Optional
21 * @since 4.7.0
22 */
23 @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public final class OptionalStep3<A, B, C> {
24
25 private final Optional<A> optional1;
26 private final Optional<B> optional2;
27 private final Optional<C> optional3;
28
29 OptionalStep3(Optional<A> optional1, Optional<B> optional2, Optional<C> optional3) {
30 this.optional1 = optional1;
31 this.optional2 = optional2;
32 this.optional3 = optional3;
33 }
34
35 /**
36 * Apply the provided function with the previous Step results.
37 * <p>
38 * Internally this will perform a {@link Optional#flatMap(Function)} and the
39 * result 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> OptionalStep4<A, B, C, D> then(Function3<? super A, ? super B, ? super C, Optional<D>> functor) {
47 Optional<D> option4 = optional1
48 .flatMap(value1 -> optional2.flatMap(value2 -> optional3.flatMap(value3 -> functor.apply(value1, value2, value3))));
49 return new OptionalStep4<>(optional1, optional2, optional3, option4);
50 }
51
52 /**
53 * Apply the provided supplier with the previous Step results.
54 * <p>
55 * Internally this will perform a {@link Optional#flatMap(Function)} and the
56 * supplier will become the next step value.
57 * <p>
58 * This is different to {@link #then(Function3)} in that the previous step
59 * results are not provided for the new step evaluation.
60 *
61 * @param supplier The supplier to provide the result of the flatMap with the
62 * previous step.
63 * @param <D> The type of the next step result
64 * @return The next step class
65 */
66 public <D> OptionalStep4<A, B, C, D> then(Supplier<Optional<D>> supplier) {
67 Optional<D> Optional = optional1.flatMap(value1 -> optional2.flatMap(value2 -> optional3.flatMap(value3 -> supplier.get())));
68 return new OptionalStep4<>(optional1, optional2, optional3, Optional);
69 }
70
71 /**
72 * Apply the provided predicate with the previous step results.
73 *
74 * @param predicate The check that must be satisfied by contained values
75 * @return This step class with either the same last step value, or changed to
76 * empty
77 */
78 public OptionalStep3<A, B, C> filter(Predicate3<? super A, ? super B, ? super C> predicate) {
79 Optional<C> filterOptional3 = optional1.flatMap(value1 -> optional2.flatMap(value2 -> optional3.filter(value3 -> predicate.test(value1, value2,
80 value3))));
81 return new OptionalStep3<>(optional1, optional2, filterOptional3);
82 }
83
84 /**
85 * Terminating step expression, that will provide the previous steps to this
86 * function and return the result as a <code>of</code>
87 *
88 * @param functor The yield function to map on previous values
89 * @param <Z> The type for the returned result
90 * @return An Optional containing this result or empty
91 */
92 public <Z> Optional<Z> yield(Function3<? super A, ? super B, ? super C, Z> functor) {
93 return optional1.flatMap(value1 -> optional2.flatMap(value2 -> optional3.map(value3 -> functor.apply(value1, value2, value3))));
94 }
95
96 }