1+ package com .cedarsoftware .io .util ;
2+
3+ import java .util .Collection ;
4+ import java .util .HashSet ;
5+ import java .util .Iterator ;
6+ import java .util .List ;
7+ import java .util .ListIterator ;
8+ import java .util .function .Supplier ;
9+
10+ import com .cedarsoftware .util .ConcurrentList ;
11+
12+ /**
13+ * SealableList provides a List or List wrapper that can be 'sealed' and 'unsealed.' When
14+ * sealed, the List is immutable, when unsealed it is mutable. The iterator(),
15+ * listIterator(), and subList() return views that honor the Supplier's sealed state.
16+ * The sealed state can be changed as often as needed.
17+ * <br><br>
18+ * NOTE: Please do not reformat this code as the current format makes it easy to see the overall structure.
19+ * <br><br>
20+ * @author John DeRegnaucourt ([email protected] ) 21+ * <br>
22+ * Copyright (c) Cedar Software LLC
23+ * <br><br>
24+ * Licensed under the Apache License, Version 2.0 (the "License");
25+ * you may not use this file except in compliance with the License.
26+ * You may obtain a copy of the License at
27+ * <br><br>
28+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">License</a>
29+ * <br><br>
30+ * Unless required by applicable law or agreed to in writing, software
31+ * distributed under the License is distributed on an "AS IS" BASIS,
32+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33+ * See the License for the specific language governing permissions and
34+ * limitations under the License.
35+ */
36+ public class SealableList <T > implements List <T > {
37+ private final List <T > list ;
38+ private final transient Supplier <Boolean > sealedSupplier ;
39+
40+ /**
41+ * Create a SealableList. Since no List is being supplied, this will use an ConcurrentList internally. If you
42+ * want to use an ArrayList for example, use SealableList constructor that takes a List and pass it the instance
43+ * you want it to wrap.
44+ * @param sealedSupplier {@code Supplier<Boolean>} that returns 'true' to indicate sealed, 'false' for mutable.
45+ */
46+ public SealableList (Supplier <Boolean > sealedSupplier ) {
47+ this .list = new ConcurrentList <>();
48+ this .sealedSupplier = sealedSupplier ;
49+ }
50+
51+ /**
52+ * Create a SealableList. Since a List is not supplied, the elements from the passed in Collection will be
53+ * copied to an internal ConcurrentList. If you want to use an ArrayList for example, use SealableList
54+ * constructor that takes a List and pass it the instance you want it to wrap.
55+ * @param col Collection to supply initial elements. These are copied to an internal ConcurrentList.
56+ * @param sealedSupplier {@code Supplier<Boolean>} that returns 'true' to indicate sealed, 'false' for mutable.
57+ */
58+ public SealableList (Collection <T > col , Supplier <Boolean > sealedSupplier ) {
59+ this .list = new ConcurrentList <>();
60+ this .list .addAll (col );
61+ this .sealedSupplier = sealedSupplier ;
62+ }
63+
64+ /**
65+ * Use this constructor to wrap a List (any kind of List) and make it a SealableList.
66+ * No duplicate of the List is created and the original list is operated on directly if unsealed, or protected
67+ * from changes if sealed.
68+ * @param list List instance to protect.
69+ * @param sealedSupplier {@code Supplier<Boolean>} that returns 'true' to indicate sealed, 'false' for mutable.
70+ */
71+ public SealableList (List <T > list , Supplier <Boolean > sealedSupplier ) {
72+ this .list = list ;
73+ this .sealedSupplier = sealedSupplier ;
74+ }
75+
76+ private void throwIfSealed () {
77+ if (sealedSupplier .get ()) {
78+ throw new UnsupportedOperationException ("This list has been sealed and is now immutable" );
79+ }
80+ }
81+
82+ // Immutable APIs
83+ public boolean equals (Object other ) { return list .equals (other ); }
84+ public int hashCode () { return list .hashCode (); }
85+ public String toString () { return list .toString (); }
86+ public int size () { return list .size (); }
87+ public boolean isEmpty () { return list .isEmpty (); }
88+ public boolean contains (Object o ) { return list .contains (o ); }
89+ public boolean containsAll (Collection <?> col ) { return new HashSet <>(list ).containsAll (col ); }
90+ public int indexOf (Object o ) { return list .indexOf (o ); }
91+ public int lastIndexOf (Object o ) { return list .lastIndexOf (o ); }
92+ public T get (int index ) { return list .get (index ); }
93+ public Object [] toArray () { return list .toArray (); }
94+ public <T1 > T1 [] toArray (T1 [] a ) { return list .toArray (a );}
95+ public Iterator <T > iterator () { return createSealHonoringIterator (list .iterator ()); }
96+ public ListIterator <T > listIterator () { return createSealHonoringListIterator (list .listIterator ()); }
97+ public ListIterator <T > listIterator (final int index ) { return createSealHonoringListIterator (list .listIterator (index )); }
98+ public List <T > subList (int fromIndex , int toIndex ) { return new SealableList <>(list .subList (fromIndex , toIndex ), sealedSupplier ); }
99+
100+ // Mutable APIs
101+ public boolean add (T t ) { throwIfSealed (); return list .add (t ); }
102+ public boolean remove (Object o ) { throwIfSealed (); return list .remove (o ); }
103+ public boolean addAll (Collection <? extends T > col ) { throwIfSealed (); return list .addAll (col ); }
104+ public boolean addAll (int index , Collection <? extends T > col ) { throwIfSealed (); return list .addAll (index , col ); }
105+ public boolean removeAll (Collection <?> col ) { throwIfSealed (); return list .removeAll (col ); }
106+ public boolean retainAll (Collection <?> col ) { throwIfSealed (); return list .retainAll (col ); }
107+ public void clear () { throwIfSealed (); list .clear (); }
108+ public T set (int index , T element ) { throwIfSealed (); return list .set (index , element ); }
109+ public void add (int index , T element ) { throwIfSealed (); list .add (index , element ); }
110+ public T remove (int index ) { throwIfSealed (); return list .remove (index ); }
111+
112+ private Iterator <T > createSealHonoringIterator (Iterator <T > iterator ) {
113+ return new Iterator <T >() {
114+ public boolean hasNext () { return iterator .hasNext (); }
115+ public T next () { return iterator .next (); }
116+ public void remove () { throwIfSealed (); iterator .remove (); }
117+ };
118+ }
119+
120+ private ListIterator <T > createSealHonoringListIterator (ListIterator <T > iterator ) {
121+ return new ListIterator <T >() {
122+ public boolean hasNext () { return iterator .hasNext ();}
123+ public T next () { return iterator .next (); }
124+ public boolean hasPrevious () { return iterator .hasPrevious (); }
125+ public T previous () { return iterator .previous (); }
126+ public int nextIndex () { return iterator .nextIndex (); }
127+ public int previousIndex () { return iterator .previousIndex (); }
128+ public void remove () { throwIfSealed (); iterator .remove (); }
129+ public void set (T e ) { throwIfSealed (); iterator .set (e ); }
130+ public void add (T e ) { throwIfSealed (); iterator .add (e );}
131+ };
132+ }
133+ }
0 commit comments