413ef742c3c7c880332878ffbfa98b21c940700e
[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 java.util.function.Consumer;
14 import java.util.function.Function;
15 import java.util.function.Supplier;
16 import javax.annotation.concurrent.ThreadSafe;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19
20 /**
21  * Utility holder similar to {@link java.util.Optional}, except the empty case contains an Exception, which should be
22  * reported, for example via throwing it. It provides analogous methods such as {@link #isPresent()},
23  * {@link #ifPresent(Consumer)}, {@link #get()}, {@link #orElse(Object)}, {@link #orElseGet(Supplier)},
24  * {@link #orElseThrow(Function)}.
25  *
26  * @param <T> Value type
27  * @param <E> Exception type
28  * @author Robert Varga
29  */
30 @Beta
31 @NonNullByDefault
32 @ThreadSafe
33 public final class CheckedValue<T, E extends Exception> extends Variant<T, E> {
34     private CheckedValue(final T value) {
35         super(value);
36     }
37
38     private CheckedValue(final E violation, final @Nullable Void dummy) {
39         super(violation, dummy);
40     }
41
42     /**
43      * Create a new instance containing an {@link Exception}.
44      *
45      * @param cause Throwable
46      * @return A new instance
47      * @throws NullPointerException if {@code cause} is null
48      */
49     public static <T, E extends Exception> CheckedValue<T, E> ofException(final E cause) {
50         return new CheckedValue<>(cause, null);
51     }
52
53     /**
54      * Create a new instance containing specified value.
55      *
56      * @param value Value
57      * @return A new instance
58      * @throws NullPointerException if {@code value} is null
59      */
60     public static <T, E extends Exception> CheckedValue<T, E> ofValue(final T value) {
61         return new CheckedValue<>(value);
62     }
63
64     /**
65      * Convert a Variant into a {@link CheckedValue}, converting the second value into an exception.
66      *
67      * @param variant Input variant
68      * @return Resulting {@link CheckedValue}
69      */
70     public static <T, U, E extends Exception> CheckedValue<T, E> ofVariant(final Variant<T, U> variant,
71             final Function<U, E> mapper) {
72         requireNonNull(mapper);
73         return variant.isFirst() ? new CheckedValue(variant.first())
74                 : new CheckedValue(mapper.apply(variant.second()), null);
75     }
76
77     /**
78      * Return the contained value if {@link #isPresent()} would return true, throws {@link IllegalStateException}
79      * otherwise.
80      *
81      * @return Contained value
82      * @throws IllegalStateException if an error string is present.
83      */
84     public T get() {
85         if (isFirst()) {
86             return first();
87         }
88         throw new IllegalStateException("Value is not present", second());
89     }
90
91     /**
92      * Return the contained error string if {@link #isPresent()} would return false, throws
93      * {@link IllegalStateException} otherwise.
94      *
95      * @return Throwable which was used to instantiate this object, or absent if it was instantiated using an error
96      *         string.
97      * @throws IllegalStateException if a value is present.
98      */
99     public E getException() {
100         if (isSecond()) {
101             return second();
102         }
103         throw new IllegalStateException("Value " + first() + " is present");
104     }
105
106     /**
107      * Return true if a value is present.
108      *
109      * @return True if a value is present.
110      */
111     public boolean isPresent() {
112         return isFirst();
113     }
114
115     /**
116      * If a value is present, invoke the specified consumer with the value, otherwise do nothing.
117      *
118      * @param consumer block to be executed if a value is present
119      * @throws NullPointerException if value is present and {@code consumer} is null
120      */
121     public void ifPresent(final Consumer<? super T> consumer) {
122         if (isFirst()) {
123             consumer.accept(first());
124         }
125     }
126
127     @SuppressWarnings("unchecked")
128     public <U> CheckedValue<U, E> map(final Function<? super T, U> mapper) {
129         requireNonNull(mapper);
130         return isFirst() ? new CheckedValue<>(mapper.apply(first())) : (CheckedValue<U, E>) this;
131     }
132
133     @SuppressWarnings("unchecked")
134     public <X extends Exception> CheckedValue<T, X> mapException(final Function<? super E, X> mapper) {
135         requireNonNull(mapper);
136         if (isFirst()) {
137             return (CheckedValue<T, X>) this;
138         }
139         return new CheckedValue<>(mapper.apply(second()), null);
140     }
141
142
143     @SuppressWarnings("unchecked")
144     public <U> CheckedValue<U, E> flatMap(final Function<? super T, CheckedValue<U, E>> mapper) {
145         requireNonNull(mapper);
146         return isFirst() ? requireNonNull(mapper.apply(first())) : (CheckedValue<U, E>) this;
147     }
148
149     /**
150      * Return contained value if present, otherwise return supplied value.
151      *
152      * @param other Replacement value
153      * @return Contained value or {code other}
154      */
155     public T orElse(final T other) {
156         return isFirst() ? first() : other;
157     }
158
159     /**
160      * Return contained value if present, otherwise return the value produced by a supplier.
161      *
162      * @param supplier Replacement value supplier
163      * @return Contained value or supplier's value
164      * @throws NullPointerException if {@code supplier} is null
165      */
166     public T orElseGet(final Supplier<T> supplier) {
167         requireNonNull(supplier);
168         return isFirst() ? first() : supplier.get();
169     }
170
171     public <X extends Throwable> T orElseThrow() throws E {
172         if (isFirst()) {
173             return first();
174         }
175         throw second();
176     }
177
178     public <X extends Throwable> T orElseThrow(final Function<E, X> exceptionMapper) throws X {
179         requireNonNull(exceptionMapper);
180         if (isFirst()) {
181             return first();
182         }
183         throw exceptionMapper.apply(second());
184     }
185
186     public <X extends Throwable> T orElseThrow(final Supplier<X> supplier) throws X {
187         requireNonNull(supplier);
188         if (isFirst()) {
189             return first();
190         }
191         throw supplier.get();
192     }
193 }