001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.collections;
014
015import java.util.*;
016import java.util.function.*;
017
018import org.apache.juneau.internal.*;
019
020/**
021 * An array list that allows you to control whether it's read-only via a constructor parameter.
022 *
023 * <p>
024 * Override methods such as {@link #overrideAdd(int, Object)} are provided that bypass the unmodifiable restriction
025 * on the list.  They allow you to manipulate the list while not exposing the ability to manipulate the list through
026 * any of the methods provided by the {@link List} interface (meaning you can pass the object around as an unmodifiable List).
027 *
028 * @param <E> The element type.
029 */
030@FluentSetters
031public class ControlledArrayList<E> extends ArrayList<E> {
032
033   private static final long serialVersionUID = -1L;
034
035   private boolean unmodifiable;
036
037   /**
038    * Constructor.
039    *
040    * @param unmodifiable If <jk>true</jk>, this list cannot be modified through normal list operation methods on the {@link List} interface.
041    */
042   public ControlledArrayList(boolean unmodifiable) {
043      this.unmodifiable = unmodifiable;
044   }
045
046   /**
047    * Constructor.
048    *
049    * @param unmodifiable If <jk>true</jk>, this list cannot be modified through normal list operation methods on the {@link List} interface.
050    * @param list The initial contents of this list.
051    */
052   public ControlledArrayList(boolean unmodifiable, List<? extends E> list) {
053      super(list);
054      this.unmodifiable = unmodifiable;
055   }
056
057   //-----------------------------------------------------------------------------------------------------------------
058   // Properties
059   //-----------------------------------------------------------------------------------------------------------------
060
061
062   /**
063    * Specifies whether this bean should be unmodifiable.
064    * <p>
065    * When enabled, attempting to set any properties on this bean will cause an {@link UnsupportedOperationException}.
066    *
067    * @return This object.
068    */
069   @FluentSetter
070   public ControlledArrayList<E> setUnmodifiable() {
071      unmodifiable = true;
072      return this;
073   }
074
075   /**
076    * Throws an {@link UnsupportedOperationException} if the unmodifiable flag is set on this bean.
077    */
078   protected final void assertModifiable() {
079      if (unmodifiable)
080         throw new UnsupportedOperationException("List is read-only");
081   }
082
083   /**
084    * Returns <jk>true</jk> if this list is modifiable.
085    *
086    * @return <jk>true</jk> if this list is modifiable.
087    */
088   public boolean isModifiable() {
089      return ! unmodifiable;
090   }
091
092   @Override
093   public E set(int index, E element) {
094      assertModifiable();
095      return overrideSet(index, element);
096   }
097
098   /**
099    * Same as {@link #set(int, Object)} but bypasses the modifiable flag.
100    *
101    * @param index Index of the element to replace.
102    * @param element Element to be stored at the specified position.
103    * @return The element previously at the specified position.
104    */
105   public E overrideSet(int index, E element) {
106      return super.set(index, element);
107   }
108
109   @Override
110   public void add(int index, E element) {
111      assertModifiable();
112      overrideAdd(index, element);
113   }
114
115   /**
116    * Same as {@link #add(int, Object)} but bypasses the modifiable flag.
117    *
118    * @param index Index of the element to replace.
119    * @param element Element to be stored at the specified position.
120    */
121   public void overrideAdd(int index, E element) {
122      super.add(index, element);
123   }
124
125   @Override
126   public E remove(int index) {
127      assertModifiable();
128      return overrideRemove(index);
129   }
130
131   /**
132    * Same as {@link #remove(int)} but bypasses the modifiable flag.
133    *
134    * @param index Index of the element to remove.
135    * @return The element that was removed from the list.
136    */
137   public E overrideRemove(int index) {
138      return super.remove(index);
139   }
140
141   @Override
142   public boolean addAll(int index, Collection<? extends E> c) {
143      assertModifiable();
144      return overrideAddAll(index, c);
145   }
146
147   /**
148    * Same as {@link #addAll(int,Collection)} but bypasses the modifiable flag.
149    *
150    * @param index Index at which to insert the first element from the specified collection.
151    * @param c Collection containing elements to be added to this list.
152    * @return <jk>true</jk> if this list changed as a result of the call.
153    */
154   public boolean overrideAddAll(int index, Collection<? extends E> c) {
155      return super.addAll(index, c);
156   }
157
158   @Override
159   public void replaceAll(UnaryOperator<E> operator) {
160      assertModifiable();
161      overrideReplaceAll(operator);
162   }
163
164   /**
165    * Same as {@link #replaceAll(UnaryOperator)} but bypasses the modifiable flag.
166    *
167    * @param operator The operator to apply to each element.
168    */
169   public void overrideReplaceAll(UnaryOperator<E> operator) {
170      super.replaceAll(operator);
171   }
172
173   @Override
174   public void sort(Comparator<? super E> c) {
175      assertModifiable();
176      overrideSort(c);
177   }
178
179   /**
180    * Same as {@link #overrideSort(Comparator)} but bypasses the modifiable flag.
181    *
182    * @param c The Comparator used to compare list elements. A null value indicates that the elements' natural ordering should be used.
183    */
184   public void overrideSort(Comparator<? super E> c) {
185      super.sort(c);
186   }
187
188   @Override
189   public boolean add(E element) {
190      assertModifiable();
191      return overrideAdd(element);
192   }
193
194   /**
195    * Same as {@link #add(Object)} but bypasses the modifiable flag.
196    *
197    * @param element Element to be stored at the specified position.
198    * @return <jk>true</jk>.
199    */
200   public boolean overrideAdd(E element) {
201      return super.add(element);
202   }
203
204   @Override
205   public boolean remove(Object o) {
206      assertModifiable();
207      return overrideRemove(o);
208   }
209
210   /**
211    * Same as {@link #remove(Object)} but bypasses the modifiable flag.
212    *
213    * @param o Element to be removed from this list, if present.
214    * @return <jk>true</jk> if this list contained the specified element.
215    */
216   public boolean overrideRemove(Object o) {
217      return super.remove(o);
218   }
219
220   @Override
221   public boolean addAll(Collection<? extends E> c) {
222      assertModifiable();
223      return overrideAddAll(c);
224   }
225
226   /**
227    * Same as {@link #addAll(Collection)} but bypasses the modifiable flag.
228    *
229    * @param c Collection containing elements to be added to this list.
230    * @return <jk>true</jk> if this list changed as a result of the call.
231    */
232   public boolean overrideAddAll(Collection<? extends E> c) {
233      return super.addAll(c);
234   }
235
236   @Override
237   public boolean removeAll(Collection<?> coll) {
238      assertModifiable();
239      return overrideRemoveAll(coll);
240   }
241
242   /**
243    * Same as {@link #removeAll(Collection)} but bypasses the modifiable flag.
244    *
245    * @param c Collection containing elements to be removed from this list.
246    * @return <jk>true</jk> if this list changed as a result of the call.
247    */
248   public boolean overrideRemoveAll(Collection<?> c) {
249      return super.removeAll(c);
250   }
251
252   @Override
253   public boolean retainAll(Collection<?> c) {
254      assertModifiable();
255      return overrideRetainAll(c);
256   }
257
258   /**
259    * Same as {@link #retainAll(Collection)} but bypasses the modifiable flag.
260    *
261    * @param c Collection containing elements to be retained in this list.
262    * @return <jk>true</jk> if this list changed as a result of the call.
263    */
264   public boolean overrideRetainAll(Collection<?> c) {
265      return super.retainAll(c);
266   }
267
268   @Override
269   public void clear() {
270      assertModifiable();
271      overrideClear();
272   }
273
274   /**
275    * Same as {@link #clear()} but bypasses the modifiable flag.
276    */
277   public void overrideClear() {
278      super.clear();
279   }
280
281   @Override
282   public boolean removeIf(Predicate<? super E> filter) {
283      assertModifiable();
284      return overrideRemoveIf(filter);
285   }
286
287   /**
288    * Same as {@link #removeIf(Predicate)} but bypasses the modifiable flag.
289    *
290    * @param filter A predicate which returns true for elements to be removed.
291    * @return <jk>true</jk> if any elements were removed.
292    */
293   public boolean overrideRemoveIf(Predicate<? super E> filter) {
294      return super.removeIf(filter);
295   }
296
297   @Override
298   public List<E> subList(int fromIndex, int toIndex) {
299      return new ControlledArrayList<>(unmodifiable, super.subList(fromIndex, toIndex));
300   }
301
302   @Override
303   public ListIterator<E> listIterator() {
304      return listIterator(0);
305   }
306
307   @Override
308   public ListIterator<E> listIterator(final int index) {
309      if (! unmodifiable)
310         return overrideListIterator(index);
311
312      return new ListIterator<>() {
313         private final ListIterator<? extends E> i = overrideListIterator(index);
314
315         @Override
316         public boolean hasNext() {
317            return i.hasNext();
318         }
319
320         @Override
321         public E next() {
322            return i.next();
323         }
324
325         @Override
326         public boolean hasPrevious() {
327            return i.hasPrevious();
328         }
329
330         @Override
331         public E previous() {
332            return i.previous();
333         }
334
335         @Override
336         public int nextIndex() {
337            return i.nextIndex();
338         }
339
340         @Override
341         public int previousIndex() {
342            return i.previousIndex();
343         }
344
345         @Override
346         public void remove() {
347            throw new UnsupportedOperationException();
348         }
349
350         @Override
351         public void set(E e) {
352            throw new UnsupportedOperationException();
353         }
354
355         @Override
356         public void add(E e) {
357            throw new UnsupportedOperationException();
358         }
359
360         @Override
361         public void forEachRemaining(Consumer<? super E> action) {
362            i.forEachRemaining(action);
363         }
364      };
365   }
366
367   /**
368    * Same as {@link #listIterator()} but bypasses the modifiable flag.
369    *
370    * @param index Index of the first element to be returned from the list iterator.
371    * @return A list iterator over the elements in this list (in proper sequence), starting at the specified position in the list.
372    */
373   public ListIterator<E> overrideListIterator(final int index) {
374      return super.listIterator(index);
375   }
376
377   @Override
378   public Iterator<E> iterator() {
379      if (! unmodifiable)
380         return overrideIterator();
381
382      return new Iterator<>() {
383         private final Iterator<? extends E> i = overrideIterator();
384
385         @Override
386         public boolean hasNext() {
387            return i.hasNext();
388         }
389
390         @Override
391         public E next() {
392            return i.next();
393         }
394
395         @Override
396         public void remove() {
397            throw new UnsupportedOperationException();
398         }
399
400         @Override
401         public void forEachRemaining(Consumer<? super E> action) {
402            i.forEachRemaining(action);
403         }
404      };
405   }
406
407   /**
408    * Same as {@link #iterator()} but bypasses the modifiable flag.
409    *
410    * @return An iterator over the elements in this list in proper sequence.
411    */
412   public Iterator<E> overrideIterator() {
413      return super.iterator();
414   }
415
416   // <FluentSetters>
417
418   // </FluentSetters>
419}