View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.internal.xml;
20  
21  import java.io.Serializable;
22  import java.util.AbstractList;
23  import java.util.AbstractMap;
24  import java.util.AbstractSet;
25  import java.util.Collection;
26  import java.util.Comparator;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.ListIterator;
30  import java.util.Map;
31  import java.util.NoSuchElementException;
32  import java.util.Properties;
33  import java.util.RandomAccess;
34  import java.util.Set;
35  import java.util.function.BiFunction;
36  import java.util.function.Function;
37  import java.util.function.Predicate;
38  import java.util.function.UnaryOperator;
39  
40  class ImmutableCollections {
41  
42      private static final List<?> EMPTY_LIST = new AbstractImmutableList<Object>() {
43          @Override
44          public Object get(int index) {
45              throw new IndexOutOfBoundsException();
46          }
47  
48          @Override
49          public int size() {
50              return 0;
51          }
52      };
53  
54      private static final Map<?, ?> EMPTY_MAP = new AbstractImmutableMap<Object, Object>() {
55          @Override
56          public Set<Entry<Object, Object>> entrySet() {
57              return new AbstractImmutableSet<Entry<Object, Object>>() {
58                  @Override
59                  public Iterator<Entry<Object, Object>> iterator() {
60                      return new Iterator<Entry<Object, Object>>() {
61                          @Override
62                          public boolean hasNext() {
63                              return false;
64                          }
65  
66                          @Override
67                          public Entry<Object, Object> next() {
68                              throw new NoSuchElementException();
69                          }
70                      };
71                  }
72  
73                  @Override
74                  public int size() {
75                      return 0;
76                  }
77              };
78          }
79      };
80  
81      static <E> List<E> copy(Collection<E> collection) {
82          if (collection == null) {
83              return emptyList();
84          } else if (collection instanceof AbstractImmutableList) {
85              return (List<E>) collection;
86          } else {
87              return switch (collection.size()) {
88                  case 0 -> emptyList();
89                  case 1 -> singletonList(collection.iterator().next());
90                  case 2 -> {
91                      Iterator<E> it = collection.iterator();
92                      yield new List2<>(it.next(), it.next());
93                  }
94                  default -> new ListN<>(collection);
95              };
96          }
97      }
98  
99      @SuppressWarnings("unchecked")
100     static <E> List<E> emptyList() {
101         return (List<E>) EMPTY_LIST;
102     }
103 
104     static <E> List<E> singletonList(E element) {
105         return new List1<>(element);
106     }
107 
108     static <K, V> Map<K, V> copy(Map<K, V> map) {
109         if (map == null) {
110             return emptyMap();
111         } else if (map instanceof AbstractImmutableMap) {
112             return map;
113         } else {
114             return switch (map.size()) {
115                 case 0 -> emptyMap();
116                 case 1 -> {
117                     Map.Entry<K, V> entry = map.entrySet().iterator().next();
118                     yield singletonMap(entry.getKey(), entry.getValue());
119                 }
120                 default -> new MapN<>(map);
121             };
122         }
123     }
124 
125     @SuppressWarnings("unchecked")
126     static <K, V> Map<K, V> emptyMap() {
127         return (Map<K, V>) EMPTY_MAP;
128     }
129 
130     static <K, V> Map<K, V> singletonMap(K key, V value) {
131         return new Map1<>(key, value);
132     }
133 
134     static Properties copy(Properties properties) {
135         if (properties instanceof ROProperties) {
136             return properties;
137         }
138         return new ROProperties(properties);
139     }
140 
141     private static class List1<E> extends AbstractImmutableList<E> {
142         private final E element;
143 
144         private List1(E element) {
145             this.element = element;
146         }
147 
148         @Override
149         public E get(int index) {
150             if (index == 0) {
151                 return element;
152             }
153             throw outOfBounds(index);
154         }
155 
156         @Override
157         public int size() {
158             return 1;
159         }
160     }
161 
162     private static class List2<E> extends AbstractImmutableList<E> {
163         private final E element1;
164         private final E element2;
165 
166         private List2(E element1, E element2) {
167             this.element1 = element1;
168             this.element2 = element2;
169         }
170 
171         @Override
172         public E get(int index) {
173             if (index == 0) {
174                 return element1;
175             } else if (index == 1) {
176                 return element2;
177             }
178             throw outOfBounds(index);
179         }
180 
181         @Override
182         public int size() {
183             return 2;
184         }
185     }
186 
187     private static class ListN<E> extends AbstractImmutableList<E> {
188         private final Object[] elements;
189 
190         private ListN(Collection<E> elements) {
191             this.elements = elements.toArray();
192         }
193 
194         @SuppressWarnings("unchecked")
195         @Override
196         public E get(int index) {
197             return (E) elements[index];
198         }
199 
200         @Override
201         public int size() {
202             return elements.length;
203         }
204     }
205 
206     private abstract static class AbstractImmutableList<E> extends AbstractList<E>
207             implements RandomAccess, Serializable {
208         @Override
209         public boolean add(E e) {
210             throw uoe();
211         }
212 
213         @Override
214         public boolean remove(Object o) {
215             throw uoe();
216         }
217 
218         @Override
219         public boolean addAll(Collection<? extends E> c) {
220             throw uoe();
221         }
222 
223         @Override
224         public boolean removeAll(Collection<?> c) {
225             throw uoe();
226         }
227 
228         @Override
229         public boolean retainAll(Collection<?> c) {
230             throw uoe();
231         }
232 
233         @Override
234         public void clear() {
235             throw uoe();
236         }
237 
238         @Override
239         public boolean removeIf(Predicate<? super E> filter) {
240             throw uoe();
241         }
242 
243         @Override
244         public void replaceAll(UnaryOperator<E> operator) {
245             throw uoe();
246         }
247 
248         @Override
249         public void sort(Comparator<? super E> c) {
250             throw uoe();
251         }
252 
253         @Override
254         public Iterator<E> iterator() {
255             return new Itr(0);
256         }
257 
258         @Override
259         public ListIterator<E> listIterator() {
260             return new Itr(0);
261         }
262 
263         @Override
264         public ListIterator<E> listIterator(int index) {
265             if (index < 0 || index > size()) {
266                 throw outOfBounds(index);
267             }
268             return new Itr(index);
269         }
270 
271         @Override
272         public List<E> subList(int fromIndex, int toIndex) {
273             if (fromIndex < 0) {
274                 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
275             }
276             if (toIndex > size()) {
277                 throw new IndexOutOfBoundsException("toIndex = " + toIndex);
278             }
279             if (fromIndex > toIndex) {
280                 throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
281             }
282             return new SubList(fromIndex, toIndex);
283         }
284 
285         protected IndexOutOfBoundsException outOfBounds(int index) {
286             return new IndexOutOfBoundsException("Index: " + index + ", Size: " + size());
287         }
288 
289         private class SubList extends AbstractImmutableList<E> {
290             private final int fromIndex;
291             private final int toIndex;
292 
293             private SubList(int fromIndex, int toIndex) {
294                 this.fromIndex = fromIndex;
295                 this.toIndex = toIndex;
296             }
297 
298             @Override
299             public E get(int index) {
300                 if (index < 0 || index > size()) {
301                     throw outOfBounds(index);
302                 }
303                 return AbstractImmutableList.this.get(fromIndex + index);
304             }
305 
306             @Override
307             public int size() {
308                 return toIndex - fromIndex;
309             }
310         }
311 
312         private class Itr implements ListIterator<E> {
313             int index;
314 
315             private Itr(int index) {
316                 this.index = index;
317             }
318 
319             @Override
320             public boolean hasNext() {
321                 return index < size();
322             }
323 
324             @Override
325             public E next() {
326                 return get(index++);
327             }
328 
329             @Override
330             public boolean hasPrevious() {
331                 return index > 0;
332             }
333 
334             @Override
335             public E previous() {
336                 return get(--index);
337             }
338 
339             @Override
340             public int nextIndex() {
341                 return index;
342             }
343 
344             @Override
345             public int previousIndex() {
346                 return index - 1;
347             }
348 
349             @Override
350             public void remove() {
351                 throw uoe();
352             }
353 
354             @Override
355             public void set(E e) {
356                 throw uoe();
357             }
358 
359             @Override
360             public void add(E e) {
361                 throw uoe();
362             }
363         }
364     }
365 
366     private static class ROProperties extends Properties {
367         private ROProperties(Properties props) {
368             super();
369             if (props != null) {
370                 // Do not use super.putAll, as it may delegate to put which throws an UnsupportedOperationException
371                 for (Map.Entry<Object, Object> e : props.entrySet()) {
372                     super.put(e.getKey(), e.getValue());
373                 }
374             }
375         }
376 
377         @Override
378         public Object put(Object key, Object value) {
379             throw uoe();
380         }
381 
382         @Override
383         public Object remove(Object key) {
384             throw uoe();
385         }
386 
387         @Override
388         public void putAll(Map<?, ?> t) {
389             throw uoe();
390         }
391 
392         @Override
393         public void clear() {
394             throw uoe();
395         }
396 
397         @Override
398         public void replaceAll(BiFunction<? super Object, ? super Object, ?> function) {
399             throw uoe();
400         }
401 
402         @Override
403         public Object putIfAbsent(Object key, Object value) {
404             throw uoe();
405         }
406 
407         @Override
408         public boolean remove(Object key, Object value) {
409             throw uoe();
410         }
411 
412         @Override
413         public boolean replace(Object key, Object oldValue, Object newValue) {
414             throw uoe();
415         }
416 
417         @Override
418         public Object replace(Object key, Object value) {
419             throw uoe();
420         }
421 
422         @Override
423         public Object computeIfAbsent(Object key, Function<? super Object, ?> mappingFunction) {
424             throw uoe();
425         }
426 
427         @Override
428         public Object computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
429             throw uoe();
430         }
431 
432         @Override
433         public Object compute(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
434             throw uoe();
435         }
436 
437         @Override
438         public Object merge(Object key, Object value, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
439             throw uoe();
440         }
441     }
442 
443     private static class Map1<K, V> extends AbstractImmutableMap<K, V> {
444         private final Entry<K, V> entry;
445 
446         private Map1(K key, V value) {
447             this.entry = new SimpleImmutableEntry<>(key, value);
448         }
449 
450         @Override
451         public Set<Entry<K, V>> entrySet() {
452             return new AbstractImmutableSet<Entry<K, V>>() {
453                 @Override
454                 public Iterator<Entry<K, V>> iterator() {
455                     return new Iterator<Entry<K, V>>() {
456                         int index = 0;
457 
458                         @Override
459                         public boolean hasNext() {
460                             return index == 0;
461                         }
462 
463                         @Override
464                         public Entry<K, V> next() {
465                             if (index++ == 0) {
466                                 return entry;
467                             }
468                             throw new NoSuchElementException();
469                         }
470                     };
471                 }
472 
473                 @Override
474                 public int size() {
475                     return 1;
476                 }
477             };
478         }
479     }
480 
481     private static class MapN<K, V> extends AbstractImmutableMap<K, V> {
482         private final Object[] entries;
483 
484         private MapN(Map<K, V> map) {
485             if (map != null) {
486                 entries = new Object[map.size()];
487                 int idx = 0;
488                 for (Entry<K, V> e : map.entrySet()) {
489                     entries[idx++] = new SimpleImmutableEntry<>(e.getKey(), e.getValue());
490                 }
491             } else {
492                 entries = new Object[0];
493             }
494         }
495 
496         @Override
497         public Set<Entry<K, V>> entrySet() {
498             return new AbstractImmutableSet<Entry<K, V>>() {
499                 @Override
500                 public Iterator<Entry<K, V>> iterator() {
501                     return new Iterator<Entry<K, V>>() {
502                         int index = 0;
503 
504                         @Override
505                         public boolean hasNext() {
506                             return index < entries.length;
507                         }
508 
509                         @SuppressWarnings("unchecked")
510                         @Override
511                         public Entry<K, V> next() {
512                             if (index < entries.length) {
513                                 return (Entry<K, V>) entries[index++];
514                             }
515                             throw new NoSuchElementException();
516                         }
517                     };
518                 }
519 
520                 @Override
521                 public int size() {
522                     return entries.length;
523                 }
524             };
525         }
526     }
527 
528     private abstract static class AbstractImmutableMap<K, V> extends AbstractMap<K, V> implements Serializable {
529         @Override
530         public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
531             throw uoe();
532         }
533 
534         @Override
535         public V putIfAbsent(K key, V value) {
536             throw uoe();
537         }
538 
539         @Override
540         public boolean remove(Object key, Object value) {
541             throw uoe();
542         }
543 
544         @Override
545         public boolean replace(K key, V oldValue, V newValue) {
546             throw uoe();
547         }
548 
549         @Override
550         public V replace(K key, V value) {
551             throw uoe();
552         }
553 
554         @Override
555         public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
556             throw uoe();
557         }
558 
559         @Override
560         public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
561             throw uoe();
562         }
563 
564         @Override
565         public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
566             throw uoe();
567         }
568 
569         @Override
570         public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
571             throw uoe();
572         }
573     }
574 
575     private abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
576         @Override
577         public boolean removeAll(Collection<?> c) {
578             throw uoe();
579         }
580 
581         @Override
582         public boolean add(E e) {
583             throw uoe();
584         }
585 
586         @Override
587         public boolean remove(Object o) {
588             throw uoe();
589         }
590 
591         @Override
592         public boolean retainAll(Collection<?> c) {
593             throw uoe();
594         }
595 
596         @Override
597         public void clear() {
598             throw uoe();
599         }
600 
601         @Override
602         public boolean removeIf(Predicate<? super E> filter) {
603             throw uoe();
604         }
605     }
606 
607     private static UnsupportedOperationException uoe() {
608         return new UnsupportedOperationException();
609     }
610 }