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