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.api.model;
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              switch (collection.size()) {
88                  case 0:
89                      return emptyList();
90                  case 1:
91                      return singletonList(collection.iterator().next());
92                  case 2:
93                      Iterator<E> it = collection.iterator();
94                      return new List2<>(it.next(), it.next());
95                  default:
96                      return new ListN<>(collection);
97              }
98          }
99      }
100 
101     @SuppressWarnings("unchecked")
102     static <E> List<E> emptyList() {
103         return (List<E>) EMPTY_LIST;
104     }
105 
106     static <E> List<E> singletonList(E element) {
107         return new List1<>(element);
108     }
109 
110     static <K, V> Map<K, V> copy(Map<K, V> map) {
111         if (map == null) {
112             return emptyMap();
113         } else if (map instanceof AbstractImmutableMap) {
114             return map;
115         } else {
116             switch (map.size()) {
117                 case 0:
118                     return emptyMap();
119                 case 1:
120                     Map.Entry<K, V> entry = map.entrySet().iterator().next();
121                     return singletonMap(entry.getKey(), entry.getValue());
122                 default:
123                     return new MapN<>(map);
124             }
125         }
126     }
127 
128     @SuppressWarnings("unchecked")
129     static <K, V> Map<K, V> emptyMap() {
130         return (Map<K, V>) EMPTY_MAP;
131     }
132 
133     static <K, V> Map<K, V> singletonMap(K key, V value) {
134         return new Map1<>(key, value);
135     }
136 
137     static Properties copy(Properties properties) {
138         if (properties instanceof ROProperties) {
139             return properties;
140         }
141         return new ROProperties(properties);
142     }
143 
144     private static class List1<E> extends AbstractImmutableList<E> {
145         private final E element;
146 
147         private List1(E element) {
148             this.element = element;
149         }
150 
151         @Override
152         public E get(int index) {
153             if (index == 0) {
154                 return element;
155             }
156             throw outOfBounds(index);
157         }
158 
159         @Override
160         public int size() {
161             return 1;
162         }
163     }
164 
165     private static class List2<E> extends AbstractImmutableList<E> {
166         private final E element1;
167         private final E element2;
168 
169         private List2(E element1, E element2) {
170             this.element1 = element1;
171             this.element2 = element2;
172         }
173 
174         @Override
175         public E get(int index) {
176             if (index == 0) {
177                 return element1;
178             } else if (index == 1) {
179                 return element2;
180             }
181             throw outOfBounds(index);
182         }
183 
184         @Override
185         public int size() {
186             return 2;
187         }
188     }
189 
190     private static class ListN<E> extends AbstractImmutableList<E> {
191         private final Object[] elements;
192 
193         private ListN(Collection<E> elements) {
194             this.elements = elements.toArray();
195         }
196 
197         @SuppressWarnings("unchecked")
198         @Override
199         public E get(int index) {
200             return (E) elements[index];
201         }
202 
203         @Override
204         public int size() {
205             return elements.length;
206         }
207     }
208 
209     private abstract static class AbstractImmutableList<E> extends AbstractList<E>
210             implements RandomAccess, Serializable {
211         @Override
212         public boolean add(E e) {
213             throw uoe();
214         }
215 
216         @Override
217         public boolean remove(Object o) {
218             throw uoe();
219         }
220 
221         @Override
222         public boolean addAll(Collection<? extends E> c) {
223             throw uoe();
224         }
225 
226         @Override
227         public boolean removeAll(Collection<?> c) {
228             throw uoe();
229         }
230 
231         @Override
232         public boolean retainAll(Collection<?> c) {
233             throw uoe();
234         }
235 
236         @Override
237         public void clear() {
238             throw uoe();
239         }
240 
241         @Override
242         public boolean removeIf(Predicate<? super E> filter) {
243             throw uoe();
244         }
245 
246         @Override
247         public void replaceAll(UnaryOperator<E> operator) {
248             throw uoe();
249         }
250 
251         @Override
252         public void sort(Comparator<? super E> c) {
253             throw uoe();
254         }
255 
256         @Override
257         public Iterator<E> iterator() {
258             return new Itr(0);
259         }
260 
261         @Override
262         public ListIterator<E> listIterator() {
263             return new Itr(0);
264         }
265 
266         @Override
267         public ListIterator<E> listIterator(int index) {
268             if (index < 0 || index > size()) {
269                 throw outOfBounds(index);
270             }
271             return new Itr(index);
272         }
273 
274         @Override
275         public List<E> subList(int fromIndex, int toIndex) {
276             if (fromIndex < 0) {
277                 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
278             }
279             if (toIndex > size()) {
280                 throw new IndexOutOfBoundsException("toIndex = " + toIndex);
281             }
282             if (fromIndex > toIndex) {
283                 throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
284             }
285             return new SubList(fromIndex, toIndex);
286         }
287 
288         protected IndexOutOfBoundsException outOfBounds(int index) {
289             return new IndexOutOfBoundsException("Index: " + index + ", Size: " + size());
290         }
291 
292         private class SubList extends AbstractImmutableList<E> {
293             private final int fromIndex;
294             private final int toIndex;
295 
296             private SubList(int fromIndex, int toIndex) {
297                 this.fromIndex = fromIndex;
298                 this.toIndex = toIndex;
299             }
300 
301             @Override
302             public E get(int index) {
303                 if (index < 0 || index > size()) {
304                     throw outOfBounds(index);
305                 }
306                 return AbstractImmutableList.this.get(fromIndex + index);
307             }
308 
309             @Override
310             public int size() {
311                 return toIndex - fromIndex;
312             }
313         }
314 
315         private class Itr implements ListIterator<E> {
316             int index;
317 
318             private Itr(int index) {
319                 this.index = index;
320             }
321 
322             @Override
323             public boolean hasNext() {
324                 return index < size();
325             }
326 
327             @Override
328             public E next() {
329                 return get(index++);
330             }
331 
332             @Override
333             public boolean hasPrevious() {
334                 return index > 0;
335             }
336 
337             @Override
338             public E previous() {
339                 return get(--index);
340             }
341 
342             @Override
343             public int nextIndex() {
344                 return index;
345             }
346 
347             @Override
348             public int previousIndex() {
349                 return index - 1;
350             }
351 
352             @Override
353             public void remove() {
354                 throw uoe();
355             }
356 
357             @Override
358             public void set(E e) {
359                 throw uoe();
360             }
361 
362             @Override
363             public void add(E e) {
364                 throw uoe();
365             }
366         }
367     }
368 
369     private static class ROProperties extends Properties {
370         private ROProperties(Properties props) {
371             super();
372             if (props != null) {
373                 // Do not use super.putAll, as it may delegate to put which throws an UnsupportedOperationException
374                 for (Map.Entry<Object, Object> e : props.entrySet()) {
375                     super.put(e.getKey(), e.getValue());
376                 }
377             }
378         }
379 
380         @Override
381         public Object put(Object key, Object value) {
382             throw uoe();
383         }
384 
385         @Override
386         public Object remove(Object key) {
387             throw uoe();
388         }
389 
390         @Override
391         public void putAll(Map<?, ?> t) {
392             throw uoe();
393         }
394 
395         @Override
396         public void clear() {
397             throw uoe();
398         }
399 
400         @Override
401         public void replaceAll(BiFunction<? super Object, ? super Object, ?> function) {
402             throw uoe();
403         }
404 
405         @Override
406         public Object putIfAbsent(Object key, Object value) {
407             throw uoe();
408         }
409 
410         @Override
411         public boolean remove(Object key, Object value) {
412             throw uoe();
413         }
414 
415         @Override
416         public boolean replace(Object key, Object oldValue, Object newValue) {
417             throw uoe();
418         }
419 
420         @Override
421         public Object replace(Object key, Object value) {
422             throw uoe();
423         }
424 
425         @Override
426         public Object computeIfAbsent(Object key, Function<? super Object, ?> mappingFunction) {
427             throw uoe();
428         }
429 
430         @Override
431         public Object computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
432             throw uoe();
433         }
434 
435         @Override
436         public Object compute(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
437             throw uoe();
438         }
439 
440         @Override
441         public Object merge(Object key, Object value, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
442             throw uoe();
443         }
444     }
445 
446     private static class Map1<K, V> extends AbstractImmutableMap<K, V> {
447         private final Entry<K, V> entry;
448 
449         private Map1(K key, V value) {
450             this.entry = new SimpleImmutableEntry<>(key, value);
451         }
452 
453         @Override
454         public Set<Entry<K, V>> entrySet() {
455             return new AbstractImmutableSet<Entry<K, V>>() {
456                 @Override
457                 public Iterator<Entry<K, V>> iterator() {
458                     return new Iterator<Entry<K, V>>() {
459                         int index = 0;
460 
461                         @Override
462                         public boolean hasNext() {
463                             return index == 0;
464                         }
465 
466                         @Override
467                         public Entry<K, V> next() {
468                             if (index++ == 0) {
469                                 return entry;
470                             }
471                             throw new NoSuchElementException();
472                         }
473                     };
474                 }
475 
476                 @Override
477                 public int size() {
478                     return 1;
479                 }
480             };
481         }
482     }
483 
484     private static class MapN<K, V> extends AbstractImmutableMap<K, V> {
485         private final Object[] entries;
486 
487         private MapN(Map<K, V> map) {
488             if (map != null) {
489                 entries = new Object[map.size()];
490                 int idx = 0;
491                 for (Map.Entry<K, V> e : map.entrySet()) {
492                     entries[idx++] = new SimpleImmutableEntry<>(e.getKey(), e.getValue());
493                 }
494             } else {
495                 entries = new Object[0];
496             }
497         }
498 
499         @Override
500         public Set<Entry<K, V>> entrySet() {
501             return new AbstractImmutableSet<Entry<K, V>>() {
502                 @Override
503                 public Iterator<Entry<K, V>> iterator() {
504                     return new Iterator<Entry<K, V>>() {
505                         int index = 0;
506 
507                         @Override
508                         public boolean hasNext() {
509                             return index < entries.length;
510                         }
511 
512                         @SuppressWarnings("unchecked")
513                         @Override
514                         public Entry<K, V> next() {
515                             if (index < entries.length) {
516                                 return (Entry<K, V>) entries[index++];
517                             }
518                             throw new NoSuchElementException();
519                         }
520                     };
521                 }
522 
523                 @Override
524                 public int size() {
525                     return entries.length;
526                 }
527             };
528         }
529     }
530 
531     private abstract static class AbstractImmutableMap<K, V> extends AbstractMap<K, V> implements Serializable {
532         @Override
533         public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
534             throw uoe();
535         }
536 
537         @Override
538         public V putIfAbsent(K key, V value) {
539             throw uoe();
540         }
541 
542         @Override
543         public boolean remove(Object key, Object value) {
544             throw uoe();
545         }
546 
547         @Override
548         public boolean replace(K key, V oldValue, V newValue) {
549             throw uoe();
550         }
551 
552         @Override
553         public V replace(K key, V value) {
554             throw uoe();
555         }
556 
557         @Override
558         public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
559             throw uoe();
560         }
561 
562         @Override
563         public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
564             throw uoe();
565         }
566 
567         @Override
568         public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
569             throw uoe();
570         }
571 
572         @Override
573         public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
574             throw uoe();
575         }
576     }
577 
578     private abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
579         @Override
580         public boolean removeAll(Collection<?> c) {
581             throw uoe();
582         }
583 
584         @Override
585         public boolean add(E e) {
586             throw uoe();
587         }
588 
589         @Override
590         public boolean remove(Object o) {
591             throw uoe();
592         }
593 
594         @Override
595         public boolean retainAll(Collection<?> c) {
596             throw uoe();
597         }
598 
599         @Override
600         public void clear() {
601             throw uoe();
602         }
603 
604         @Override
605         public boolean removeIf(Predicate<? super E> filter) {
606             throw uoe();
607         }
608     }
609 
610     private static UnsupportedOperationException uoe() {
611         return new UnsupportedOperationException();
612     }
613 }