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