Merge branch 'master' of ../controller
[yangtools.git] / common / concepts / src / main / java / org / opendaylight / yangtools / concepts / Variant.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 com.google.common.base.Verify.verifyNotNull;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.annotations.Beta;
14 import com.google.common.base.MoreObjects;
15 import com.google.common.base.MoreObjects.ToStringHelper;
16 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
17 import java.util.Objects;
18 import java.util.Optional;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21
22 /**
23  * Utility holder of a two-variant value. The class design treats both variants as equal.
24  *
25  * @param <T> First alternative type
26  * @param <U> Second alternative type
27  * @author Robert Varga
28  */
29 @Beta
30 @NonNullByDefault
31 public class Variant<T, U> implements Immutable {
32     private final @Nullable T first;
33     private final @Nullable U second;
34
35     @SuppressFBWarnings("NP_STORE_INTO_NONNULL_FIELD")
36     protected Variant(final T first) {
37         this.first = requireNonNull(first);
38         second = null;
39     }
40
41     @SuppressFBWarnings("NP_STORE_INTO_NONNULL_FIELD")
42     protected Variant(final U second, final @Nullable Void dummy) {
43         first = null;
44         this.second = requireNonNull(second);
45     }
46
47     protected final T first() {
48         return verifyNotNull(first);
49     }
50
51     protected final U second() {
52         return verifyNotNull(second);
53     }
54
55     /**
56      * Create a new instance containing specified value.
57      *
58      * @param value Value
59      * @param <T> First alternative type
60      * @param <U> Second alternative type
61      * @return A new instance
62      * @throws NullPointerException if {@code value} is null
63      */
64     public static <T, U> Variant<T, U> ofFirst(final T value) {
65         return new Variant<>(value);
66     }
67
68     /**
69      * Create a new instance containing specified value.
70      *
71      * @param value Value
72      * @param <T> First alternative type
73      * @param <U> Second alternative type
74      * @return A new instance
75      * @throws NullPointerException if {@code value} is null
76      */
77     public static <T, U> Variant<T, U> ofSecond(final U value) {
78         return new Variant<>(value, null);
79     }
80
81     public final boolean isFirst() {
82         return first != null;
83     }
84
85     public final T getFirst() {
86         return tryFirst().get();
87     }
88
89     public final Optional<T> tryFirst() {
90         return Optional.ofNullable(first);
91     }
92
93     public final boolean isSecond() {
94         return second != null;
95     }
96
97     public final U getSecond() {
98         return trySecond().get();
99     }
100
101     public final Optional<U> trySecond() {
102         return Optional.ofNullable(second);
103     }
104
105     @Override
106     public final int hashCode() {
107         return Objects.hash(first, second);
108     }
109
110     @Override
111     public final boolean equals(final @Nullable Object obj) {
112         if (obj == this) {
113             return true;
114         }
115         if (obj == null || !getClass().equals(obj.getClass())) {
116             return false;
117         }
118         final Variant<?, ?> other = (Variant<?, ?>) obj;
119         return Objects.equals(first, other.first) && Objects.equals(second, other.second);
120     }
121
122     @Override
123     public final String toString() {
124         return addToString(MoreObjects.toStringHelper(this).omitNullValues()).toString();
125     }
126
127     protected ToStringHelper addToString(final ToStringHelper helper) {
128         return helper.add("first", first).add("second", second);
129     }
130 }