1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */

15
16 package software.amazon.awssdk.utils;
17
18 import java.util.AbstractMap.SimpleImmutableEntry;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.function.BiConsumer;
26 import java.util.function.BiFunction;
27 import java.util.function.Consumer;
28 import java.util.function.Function;
29 import software.amazon.awssdk.annotations.SdkInternalApi;
30
31 /**
32  * An unmodifiable view of a {@code Map<T, List<U>>}. Created using {@link CollectionUtils#unmodifiableMapOfLists(Map)}.
33  */

34 @SdkInternalApi
35 class UnmodifiableMapOfLists<T, U> implements Map<T, List<U>> {
36     private final Map<T, List<U>> delegate;
37
38     UnmodifiableMapOfLists(Map<T, List<U>> delegate) {
39         this.delegate = delegate;
40     }
41
42     @Override
43     public int size() {
44         return delegate.size();
45     }
46
47     @Override
48     public boolean isEmpty() {
49         return delegate.isEmpty();
50     }
51
52     @Override
53     public boolean containsKey(Object key) {
54         return delegate.containsKey(key);
55     }
56
57     @Override
58     public boolean containsValue(Object value) {
59         return delegate.containsValue(value);
60     }
61
62     @Override
63     public List<U> get(Object key) {
64         return delegate.get(key);
65     }
66
67     @Override
68     public List<U> getOrDefault(Object key, List<U> defaultValue) {
69         return unmodifiableList(delegate.getOrDefault(key, defaultValue));
70     }
71
72     @Override
73     public List<U> put(T key, List<U> value) {
74         throw new UnsupportedOperationException();
75     }
76
77     @Override
78     public List<U> remove(Object key) {
79         throw new UnsupportedOperationException();
80     }
81
82     @Override
83     public void putAll(Map<? extends T, ? extends List<U>> m) {
84         throw new UnsupportedOperationException();
85     }
86
87     @Override
88     public void clear() {
89         throw new UnsupportedOperationException();
90     }
91
92     @Override
93     public Set<T> keySet() {
94         return Collections.unmodifiableSet(delegate.keySet());
95     }
96
97     @Override
98     public Collection<List<U>> values() {
99         return new UnmodifiableCollection<>(delegate.values());
100     }
101
102     @Override
103     public Set<Entry<T, List<U>>> entrySet() {
104         Set<? extends Entry<T, ? extends List<U>>> entries = delegate.entrySet();
105         return new UnmodifiableEntrySet<>(entries);
106     }
107
108     @Override
109     public void forEach(BiConsumer<? super T, ? super List<U>> action) {
110         delegate.forEach((k, v) -> action.accept(k, unmodifiableList(v)));
111     }
112
113     @Override
114     public void replaceAll(BiFunction<? super T, ? super List<U>, ? extends List<U>> function) {
115         throw new UnsupportedOperationException();
116     }
117
118     @Override
119     public List<U> putIfAbsent(T key, List<U> value) {
120         throw new UnsupportedOperationException();
121     }
122
123     @Override
124     public boolean remove(Object key, Object value) {
125         throw new UnsupportedOperationException();
126     }
127
128     @Override
129     public boolean replace(T key, List<U> oldValue, List<U> newValue) {
130         throw new UnsupportedOperationException();
131     }
132
133     @Override
134     public List<U> replace(T key, List<U> value) {
135         throw new UnsupportedOperationException();
136     }
137
138     @Override
139     public List<U> computeIfAbsent(T key, Function<? super T, ? extends List<U>> mappingFunction) {
140         throw new UnsupportedOperationException();
141     }
142
143     @Override
144     public List<U> computeIfPresent(T key, BiFunction<? super T, ? super List<U>, ? extends List<U>> remappingFunction) {
145         throw new UnsupportedOperationException();
146     }
147
148     @Override
149     public List<U> compute(T key, BiFunction<? super T, ? super List<U>, ? extends List<U>> remappingFunction) {
150         throw new UnsupportedOperationException();
151     }
152
153     @Override
154     public List<U> merge(T key, List<U> value,
155                          BiFunction<? super List<U>, ? super List<U>, ? extends List<U>> remappingFunction) {
156         throw new UnsupportedOperationException();
157     }
158
159     @Override
160     public int hashCode() {
161         return delegate.hashCode();
162     }
163
164     @Override
165     public boolean equals(Object obj) {
166         return delegate.equals(obj);
167     }
168
169     @Override
170     public String toString() {
171         return delegate.toString();
172     }
173
174     private static class UnmodifiableEntrySet<T, U> implements Set<Entry<T, List<U>>> {
175         private final Set<? extends Entry<T, ? extends List<U>>> delegate;
176
177         private UnmodifiableEntrySet(Set<? extends Entry<T, ? extends List<U>>> delegate) {
178             this.delegate = delegate;
179         }
180
181         @Override
182         public int size() {
183             return delegate.size();
184         }
185
186         @Override
187         public boolean isEmpty() {
188             return delegate.isEmpty();
189         }
190
191         @Override
192         public boolean contains(Object o) {
193             return delegate.contains(o);
194         }
195
196         @Override
197         public Iterator<Entry<T, List<U>>> iterator() {
198             return new UnmodifiableEntryIterator<>(delegate.iterator());
199         }
200
201         @Override
202         public void forEach(Consumer<? super Entry<T, List<U>>> action) {
203             delegate.forEach(e -> action.accept(new SimpleImmutableEntry<>(e.getKey(), unmodifiableList(e.getValue()))));
204         }
205
206         @Override
207         @SuppressWarnings("unchecked")
208         public Object[] toArray() {
209             Object[] result = delegate.toArray();
210             for (int i = 0; i < result.length; i++) {
211                 Entry<T, List<U>> e = (Entry<T, List<U>>) result[i];
212                 result[i] = new SimpleImmutableEntry<>(e.getKey(), unmodifiableList(e.getValue()));
213             }
214             return result;
215         }
216
217         @Override
218         @SuppressWarnings("unchecked")
219         public <A> A[] toArray(A[] a) {
220             // Technically this could give the caller access very brief access to the modifiable entries from a different thread,
221             // but that's on them. They had to have done it purposefully with a different thread, and it wouldn't be very
222             // reliable.
223             Object[] result = delegate.toArray(a);
224             for (int i = 0; i < result.length; i++) {
225                 Entry<T, List<U>> e = (Entry<T, List<U>>) result[i];
226                 result[i] = new SimpleImmutableEntry<>(e.getKey(), unmodifiableList(e.getValue()));
227             }
228             return (A[]) result;
229         }
230
231         @Override
232         public boolean add(Entry<T, List<U>> tListEntry) {
233             throw new UnsupportedOperationException();
234         }
235
236         @Override
237         public boolean remove(Object o) {
238             throw new UnsupportedOperationException();
239         }
240
241         @Override
242         public boolean containsAll(Collection<?> c) {
243             return delegate.containsAll(c);
244         }
245
246         @Override
247         public boolean addAll(Collection<? extends Entry<T, List<U>>> c) {
248             throw new UnsupportedOperationException();
249         }
250
251         @Override
252         public boolean retainAll(Collection<?> c) {
253             throw new UnsupportedOperationException();
254         }
255
256         @Override
257         public boolean removeAll(Collection<?> c) {
258             throw new UnsupportedOperationException();
259         }
260
261         @Override
262         public void clear() {
263             throw new UnsupportedOperationException();
264         }
265
266         @Override
267         public int hashCode() {
268             return delegate.hashCode();
269         }
270
271         @Override
272         public boolean equals(Object obj) {
273             return delegate.equals(obj);
274         }
275
276         @Override
277         public String toString() {
278             return delegate.toString();
279         }
280     }
281
282     private static class UnmodifiableEntryIterator<T, U> implements Iterator<Entry<T, List<U>>> {
283         private final Iterator<? extends Entry<T, ? extends List<U>>> delegate;
284
285         private UnmodifiableEntryIterator(Iterator<? extends Entry<T, ? extends List<U>>> delegate) {
286             this.delegate = delegate;
287         }
288
289         @Override
290         public boolean hasNext() {
291             return delegate.hasNext();
292         }
293
294         @Override
295         public Entry<T, List<U>> next() {
296             Entry<T, ? extends List<U>> next = delegate.next();
297             return new SimpleImmutableEntry<>(next.getKey(), unmodifiableList(next.getValue()));
298         }
299     }
300
301     private static class UnmodifiableCollection<U> implements Collection<List<U>> {
302         private final Collection<? extends List<U>> delegate;
303
304         private UnmodifiableCollection(Collection<? extends List<U>> delegate) {
305             this.delegate = delegate;
306         }
307
308         @Override
309         public int size() {
310             return delegate.size();
311         }
312
313         @Override
314         public boolean isEmpty() {
315             return delegate.isEmpty();
316         }
317
318         @Override
319         public boolean contains(Object o) {
320             return delegate.contains(o);
321         }
322
323         @Override
324         public Iterator<List<U>> iterator() {
325             return new UnmodifiableListIterator<>(delegate.iterator());
326         }
327
328         @Override
329         @SuppressWarnings("unchecked")
330         public Object[] toArray() {
331             Object[] result = delegate.toArray();
332             for (int i = 0; i < result.length; i++) {
333                 result[i] = unmodifiableList((List<U>) result[i]);
334             }
335             return result;
336         }
337
338         @Override
339         @SuppressWarnings("unchecked")
340         public <A> A[] toArray(A[] a) {
341             // Technically this could give the caller access very brief access to the modifiable entries from a different thread,
342             // but that's on them. They had to have done it purposefully with a different thread, and it wouldn't be very
343             // reliable.
344             Object[] result = delegate.toArray(a);
345             for (int i = 0; i < result.length; i++) {
346                 result[i] = unmodifiableList((List<U>) result[i]);
347             }
348             return (A[]) result;
349         }
350
351         @Override
352         public boolean add(List<U> us) {
353             throw new UnsupportedOperationException();
354         }
355
356         @Override
357         public boolean remove(Object o) {
358             throw new UnsupportedOperationException();
359         }
360
361         @Override
362         public boolean containsAll(Collection<?> c) {
363             return delegate.containsAll(c);
364         }
365
366         @Override
367         public boolean addAll(Collection<? extends List<U>> c) {
368             throw new UnsupportedOperationException();
369         }
370
371         @Override
372         public boolean removeAll(Collection<?> c) {
373             throw new UnsupportedOperationException();
374         }
375
376         @Override
377         public boolean retainAll(Collection<?> c) {
378             throw new UnsupportedOperationException();
379         }
380
381         @Override
382         public void clear() {
383             throw new UnsupportedOperationException();
384         }
385
386         @Override
387         public int hashCode() {
388             return delegate.hashCode();
389         }
390
391         @Override
392         public boolean equals(Object obj) {
393             return delegate.equals(obj);
394         }
395
396         @Override
397         public String toString() {
398             return delegate.toString();
399         }
400     }
401
402     private static class UnmodifiableListIterator<U> implements Iterator<List<U>> {
403         private final Iterator<? extends List<U>> delegate;
404
405         private UnmodifiableListIterator(Iterator<? extends List<U>> delegate) {
406             this.delegate = delegate;
407         }
408
409         @Override
410         public boolean hasNext() {
411             return delegate.hasNext();
412         }
413
414         @Override
415         public List<U> next() {
416             return unmodifiableList(delegate.next());
417         }
418
419         @Override
420         public int hashCode() {
421             return delegate.hashCode();
422         }
423
424         @Override
425         public boolean equals(Object obj) {
426             return delegate.equals(obj);
427         }
428
429         @Override
430         public String toString() {
431             return delegate.toString();
432         }
433     }
434
435     private static <T> List<T> unmodifiableList(List<T> list) {
436         if (list == null) {
437             return null;
438         }
439
440         return Collections.unmodifiableList(list);
441     }
442 }
443