Cleanup use of Guava library
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / SingletonSet.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.util;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import com.google.common.collect.Iterators;
14 import java.io.Serializable;
15 import java.util.Collection;
16 import java.util.Iterator;
17 import java.util.Set;
18 import javax.annotation.Nonnull;
19 import org.opendaylight.yangtools.concepts.Immutable;
20
21 /**
22  * A {@link Set} containing a single value. For some reason neither Java nor Guava provide direct access to the retained
23  * element -- which is desirable in some situations, as is the case in {@link SharedSingletonMap#entrySet()}.
24  */
25 @Beta
26 public abstract class SingletonSet<E> implements Set<E>, Immutable, Serializable {
27     private static final long serialVersionUID = 1L;
28
29     private static final SingletonSet<?> NULL_SINGLETON = new SingletonSet<Object>() {
30         private static final long serialVersionUID = 1L;
31
32         @Override
33         @SuppressWarnings("checkstyle:parameterName")
34         public boolean contains(final Object o) {
35             return o == null;
36         }
37
38         @Override
39         @SuppressWarnings("checkstyle:equalsHashCode")
40         public int hashCode() {
41             return 0;
42         }
43
44         @Override
45         public Object getElement() {
46             return null;
47         }
48
49         @Override
50         public String toString() {
51             return "[null]";
52         }
53
54         private Object readResolve() {
55             return NULL_SINGLETON;
56         }
57     };
58
59     @SuppressWarnings("unchecked")
60     public static <E> SingletonSet<E> of(@Nonnull final E element) {
61         if (element == null) {
62             return (SingletonSet<E>) NULL_SINGLETON;
63         }
64         return new RegularSingletonSet<>(element);
65     }
66
67     public abstract E getElement();
68
69     @Override
70     public final int size() {
71         return 1;
72     }
73
74     @Override
75     public final boolean isEmpty() {
76         return false;
77     }
78
79     @Override
80     public final Iterator<E> iterator() {
81         return Iterators.singletonIterator(getElement());
82     }
83
84     @Nonnull
85     @Override
86     public final Object[] toArray() {
87         return new Object[] { getElement() };
88     }
89
90     @Nonnull
91     @SuppressWarnings({ "unchecked", "checkstyle:parameterName" })
92     @Override
93     public final <T> T[] toArray(@Nonnull final T[] a) {
94         if (a.length > 0) {
95             a[0] = (T)getElement();
96             return a;
97         }
98
99         return (T[]) new Object[] {getElement()};
100     }
101
102     @Override
103     @SuppressWarnings("checkstyle:parameterName")
104     public final boolean add(final E e) {
105         throw new UnsupportedOperationException();
106     }
107
108     @Override
109     @SuppressWarnings("checkstyle:parameterName")
110     public final boolean remove(final Object o) {
111         throw new UnsupportedOperationException();
112     }
113
114     @Override
115     @SuppressWarnings("checkstyle:parameterName")
116     public final boolean containsAll(@Nonnull final Collection<?> c) {
117         if (c.isEmpty()) {
118             return true;
119         }
120         if (c.size() != 1) {
121             return false;
122         }
123
124         return otherContains(c);
125     }
126
127     @Override
128     @SuppressWarnings("checkstyle:parameterName")
129     public final boolean addAll(@Nonnull final Collection<? extends E> c) {
130         throw new UnsupportedOperationException();
131     }
132
133     @Override
134     @SuppressWarnings("checkstyle:parameterName")
135     public final boolean retainAll(@Nonnull final Collection<?> c) {
136         throw new UnsupportedOperationException();
137     }
138
139     @Override
140     @SuppressWarnings("checkstyle:parameterName")
141     public final boolean removeAll(@Nonnull final Collection<?> c) {
142         throw new UnsupportedOperationException();
143     }
144
145     @Override
146     public final void clear() {
147         throw new UnsupportedOperationException();
148     }
149
150     @Override
151     public abstract int hashCode();
152
153     @Override
154     @SuppressWarnings("checkstyle:equalsHashCode")
155     public final boolean equals(final Object obj) {
156         if (obj == this) {
157             return true;
158         }
159         if (!(obj instanceof Set)) {
160             return false;
161         }
162
163         final Set<?> s = (Set<?>)obj;
164         return s.size() == 1 && otherContains(s);
165     }
166
167     private boolean otherContains(final Collection<?> other) {
168         try {
169             return other.contains(getElement());
170         } catch (ClassCastException | NullPointerException e) {
171             return false;
172         }
173     }
174
175     private static final class RegularSingletonSet<E> extends SingletonSet<E> {
176         private static final long serialVersionUID = 1L;
177         private final E element;
178
179         RegularSingletonSet(final E element) {
180             this.element = requireNonNull(element);
181         }
182
183         @Override
184         @SuppressWarnings("checkstyle:parameterName")
185         public boolean contains(final Object o) {
186             return element.equals(o);
187         }
188
189         @Override
190         public E getElement() {
191             return element;
192         }
193
194         @Override
195         @SuppressWarnings("checkstyle:equalsHashCode")
196         public int hashCode() {
197             return getElement().hashCode();
198         }
199
200         @Override
201         public String toString() {
202             return "[" + element + ']';
203         }
204     }
205 }