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}