Merge branch 'master' of ../controller
[yangtools.git] / common / concepts / src / main / java / org / opendaylight / yangtools / concepts / CheckedValue.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.concepts;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import com.google.common.util.concurrent.FluentFuture;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import com.google.common.util.concurrent.SettableFuture;
17 import java.util.concurrent.CompletableFuture;
18 import java.util.function.Consumer;
19 import java.util.function.Function;
20 import java.util.function.Supplier;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23
24 /**
25  * Utility holder similar to {@link java.util.Optional}, except the empty case contains an Exception, which should be
26  * reported, for example via throwing it. It provides analogous methods such as {@link #isPresent()},
27  * {@link #ifPresent(Consumer)}, {@link #get()}, {@link #orElse(Object)}, {@link #orElseGet(Supplier)},
28  * {@link #orElseThrow(Function)}.
29  *
30  * @param <T> Value type
31  * @param <E> Exception type
32  * @author Robert Varga
33  */
34 @Beta
35 @NonNullByDefault
36 public class CheckedValue<T, E extends Exception> extends Variant<T, E> {
37     protected CheckedValue(final T value) {
38         super(value);
39     }
40
41     protected CheckedValue(final E violation, final @Nullable Void dummy) {
42         super(violation, dummy);
43     }
44
45     /**
46      * Create a new instance containing an {@link Exception}.
47      *
48      * @param cause Throwable
49      * @param <T> Value type
50      * @param <E> Exception type
51      * @return A new instance
52      * @throws NullPointerException if {@code cause} is null
53      */
54     public static <T, E extends Exception> CheckedValue<T, E> ofException(final E cause) {
55         return new CheckedValue<>(cause, null);
56     }
57
58     /**
59      * Create a new instance containing specified value.
60      *
61      * @param value Value
62      * @param <T> Value type
63      * @param <E> Exception type
64      * @return A new instance
65      * @throws NullPointerException if {@code value} is null
66      */
67     public static <T, E extends Exception> CheckedValue<T, E> ofValue(final T value) {
68         return new CheckedValue<>(value);
69     }
70
71     /**
72      * Convert a Variant into a {@link CheckedValue}, converting the second value into an exception.
73      *
74      * @param variant Input variant
75      * @param mapper Mapping function from second alternative to an exception
76      * @param <T> First alternative type
77      * @param <U> Second alternative type
78      * @param <E> Exception type
79      * @return Resulting {@link CheckedValue}
80      */
81     public static <T, U, E extends Exception> CheckedValue<T, E> ofVariant(final Variant<T, U> variant,
82             final Function<U, E> mapper) {
83         requireNonNull(mapper);
84         return variant.isFirst() ? new CheckedValue<>(variant.first())
85                 : new CheckedValue<>(mapper.apply(variant.second()), null);
86     }
87
88     /**
89      * Return the contained value if {@link #isPresent()} would return true, throws {@link IllegalStateException}
90      * otherwise.
91      *
92      * @return Contained value
93      * @throws IllegalStateException if an error string is present.
94      */
95     public final T get() {
96         if (isFirst()) {
97             return first();
98         }
99         throw new IllegalStateException("Value is not present", second());
100     }
101
102     /**
103      * Return the contained error string if {@link #isPresent()} would return false, throws
104      * {@link IllegalStateException} otherwise.
105      *
106      * @return Throwable which was used to instantiate this object, or absent if it was instantiated using an error
107      *         string.
108      * @throws IllegalStateException if a value is present.
109      */
110     public final E getException() {
111         if (isSecond()) {
112             return second();
113         }
114         throw new IllegalStateException("Value " + first() + " is present");
115     }
116
117     /**
118      * Return true if a value is present.
119      *
120      * @return True if a value is present.
121      */
122     public final boolean isPresent() {
123         return isFirst();
124     }
125
126     /**
127      * If a value is present, invoke the specified consumer with the value, otherwise do nothing.
128      *
129      * @param consumer block to be executed if a value is present
130      * @throws NullPointerException if value is present and {@code consumer} is null
131      */
132     public final void ifPresent(final Consumer<? super T> consumer) {
133         if (isFirst()) {
134             consumer.accept(first());
135         }
136     }
137
138     @SuppressWarnings("unchecked")
139     public <U> CheckedValue<U, E> map(final Function<? super T, U> mapper) {
140         requireNonNull(mapper);
141         return isFirst() ? new CheckedValue<>(mapper.apply(first())) : (CheckedValue<U, E>) this;
142     }
143
144     @SuppressWarnings("unchecked")
145     public <X extends Exception> CheckedValue<T, X> mapException(final Function<? super E, X> mapper) {
146         requireNonNull(mapper);
147         if (isFirst()) {
148             return (CheckedValue<T, X>) this;
149         }
150         return new CheckedValue<>(mapper.apply(second()), null);
151     }
152
153
154     @SuppressWarnings("unchecked")
155     public <U> CheckedValue<U, E> flatMap(final Function<? super T, CheckedValue<U, E>> mapper) {
156         requireNonNull(mapper);
157         return isFirst() ? requireNonNull(mapper.apply(first())) : (CheckedValue<U, E>) this;
158     }
159
160     /**
161      * Return contained value if present, otherwise return supplied value.
162      *
163      * @param other Replacement value
164      * @return Contained value or {code other}
165      */
166     public final T orElse(final T other) {
167         return isFirst() ? first() : other;
168     }
169
170     /**
171      * Return contained value if present, otherwise return the value produced by a supplier.
172      *
173      * @param supplier Replacement value supplier
174      * @return Contained value or supplier's value
175      * @throws NullPointerException if {@code supplier} is null
176      */
177     public final T orElseGet(final Supplier<T> supplier) {
178         requireNonNull(supplier);
179         return isFirst() ? first() : supplier.get();
180     }
181
182     /**
183      * Return contained value if present or throw the exception alternative.
184      *
185      * @return Contained value
186      * @throws E When there is no contained value
187      */
188     public final T orElseThrow() throws E {
189         if (isFirst()) {
190             return first();
191         }
192         throw second();
193     }
194
195     /**
196      * Return contained value if present or throw the exception alternative mapped through provided mapper.
197      *
198      * @param exceptionMapper Exception mapper
199      * @param <X> Thrown exception type
200      * @return Contained value
201      * @throws NullPointerException if {@code exceptionMapper} is null
202      * @throws X When there is no contained value
203      */
204     public final <X extends Throwable> T orElseThrow(final Function<E, X> exceptionMapper) throws X {
205         requireNonNull(exceptionMapper);
206         if (isFirst()) {
207             return first();
208         }
209         throw exceptionMapper.apply(second());
210     }
211
212     /**
213      * Return contained value if present or throw the exception supplied by supplier.
214      *
215      * @param supplier Exception supplier
216      * @param <X> Thrown exception type
217      * @return Contained value
218      * @throws NullPointerException if {@code exceptionMapper} is null
219      * @throws X When there is no contained value
220      */
221     public final <X extends Throwable> T orElseThrow(final Supplier<X> supplier) throws X {
222         requireNonNull(supplier);
223         if (isFirst()) {
224             return first();
225         }
226         throw supplier.get();
227     }
228
229     /**
230      * Complete target {@link CompletableFuture} either successfully or exceptionally based on the state of this object.
231      *
232      * @param future Future to complete
233      * @return True if this call has transitioned the future to a completed state, false otherwise.
234      * @throws NullPointerException if {code future} is null
235      */
236     public final boolean completeFuture(final CompletableFuture<T> future) {
237         return isFirst() ? future.complete(first()) : future.completeExceptionally(second());
238     }
239
240     /**
241      * Complete target {@link SettableFuture} either successfully or exceptionally based on the state of this object.
242      *
243      * @param future Future to complete
244      * @return True if this call has transitioned the future to a completed state, false otherwise.
245      * @throws NullPointerException if {code future} is null
246      */
247     public final boolean completeFuture(final SettableFuture<T> future) {
248         return isFirst() ? future.set(first()) : future.setException(second());
249     }
250
251     /**
252      * Transform this object into an immediately-completed {@link CompletableFuture}. The future will be successful
253      * if this object has a contained value or unsuccessful if this objects contains an exception.
254      *
255      * @return A {@link CompletableFuture}.
256      */
257     public final CompletableFuture<T> toCompletableFuture() {
258         if (isFirst()) {
259             return CompletableFuture.completedFuture(first());
260         }
261         // FIXME: Java 9: use CompletableFuture.failedFuture()
262         final CompletableFuture<T> future = new CompletableFuture<>();
263         future.completeExceptionally(second());
264         return future;
265     }
266
267     /**
268      * Transform this object into an immediately-completed {@link FluentFuture}. The future will be successful
269      * if this object has a contained value or unsuccessful if this objects contains an exception.
270      *
271      * @return A {@link FluentFuture}.
272      */
273     public final FluentFuture<T> toFluentFuture() {
274         final ListenableFuture<T> future;
275         if (isFirst()) {
276             future = Futures.immediateFuture(first());
277         } else {
278             future = Futures.immediateFailedFuture(second());
279         }
280         return FluentFuture.from(future);
281     }
282 }