1 /* 2 * The contents of this file are subject to the terms of the Common Development and 3 * Distribution License (the License). You may not use this file except in compliance with the 4 * License. 5 * 6 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 7 * specific language governing permission and limitations under the License. 8 * 9 * When distributing Covered Software, include this CDDL Header Notice in each file and include 10 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 11 * Header, with the fields enclosed by brackets [] replaced by your own identifying 12 * information: "Portions copyright [year] [name of copyright owner]". 13 * 14 * Copyright 2015-2016 ForgeRock AS. 15 */ 16 17 package org.forgerock.util; 18 19 // Java SE 20 import java.util.Collection; 21 import java.util.Iterator; 22 import java.util.List; 23 import java.util.ListIterator; 24 25 /** 26 * A list with lazy initialization. The factory is called to initialize the list 27 * on the first call to one of this object's methods. 28 * 29 * @param <E> 30 * The type of element contained in this list. 31 */ 32 public class LazyList<E> implements List<E> { 33 34 /** The list that this lazy list exposes, once initialized. */ 35 private List<E> list; 36 37 /** Factory to create the instance of the list to expose. */ 38 protected Factory<List<E>> factory; 39 40 /** 41 * Constructs a new lazy list. Allows factory to be set in subclass 42 * constructor. 43 */ 44 protected LazyList() { 45 } 46 47 /** 48 * Constructs a new lazy list. 49 * 50 * @param factory 51 * factory to create the list instance to expose. 52 */ 53 public LazyList(Factory<List<E>> factory) { 54 this.factory = factory; 55 } 56 57 /** 58 * Performs lazy initialization of the list if not already performed, and 59 * returns the initialized list. 60 */ 61 private List<E> lazy() { 62 if (list == null) { 63 synchronized (this) { 64 if (list == null) { 65 list = factory.newInstance(); 66 } 67 } 68 } 69 return list; 70 } 71 72 /** 73 * Returns the number of elements in this list. 74 */ 75 @Override 76 public int size() { 77 return lazy().size(); 78 } 79 80 /** 81 * Returns {@code true} if this list contains no elements. 82 */ 83 @Override 84 public boolean isEmpty() { 85 return lazy().isEmpty(); 86 } 87 88 /** 89 * Returns {@code true} if this list contains the specified element. 90 * 91 * @param o 92 * the element whose presence in this list is to be tested. 93 * @return {@code true} if this list contains the specified element. 94 */ 95 @Override 96 public boolean contains(Object o) { 97 return lazy().contains(o); 98 } 99 100 /** 101 * Returns an iterator over the elements in this list in proper sequence. 102 */ 103 @Override 104 public Iterator<E> iterator() { 105 return lazy().iterator(); 106 } 107 108 /** 109 * Returns an array containing all of the elements in this list in proper 110 * sequence (from first to last element). 111 */ 112 @Override 113 public Object[] toArray() { 114 return lazy().toArray(); 115 } 116 117 /** 118 * Returns an array containing all of the elements in this list in proper 119 * sequence (from first to last element); the runtime type of the returned 120 * array is that of the specified array. If the list fits in the specified 121 * array, it is returned therein. Otherwise, a new array is allocated with 122 * the runtime type of the specified array and the size of this list. 123 * 124 * @param a 125 * the array into which the elements of this list are to be 126 * stored. 127 * @return an array containing the elements of this list. 128 */ 129 @Override 130 public <T> T[] toArray(T[] a) { 131 return lazy().toArray(a); 132 } 133 134 /** 135 * Appends the specified element to the end of this list. 136 * 137 * @param e 138 * the element to be appended to this list. 139 * @return {@code true} if this list changed as a result of the call. 140 */ 141 @Override 142 public boolean add(E e) { 143 return lazy().add(e); 144 } 145 146 /** 147 * Removes the first occurrence of the specified element from this list, if 148 * it is present. 149 * 150 * @param o 151 * the element to be removed from this list, if present. 152 * @return true if this list contained the specified element. 153 */ 154 @Override 155 public boolean remove(Object o) { 156 return lazy().remove(o); 157 } 158 159 /** 160 * Returns {@code true} if this list contains all of the elements of the 161 * specified collection. 162 * 163 * @param c 164 * the collection to be checked for containment in this list. 165 * @return {@code true} if this list contains all of the elements of the 166 * specified collection. 167 */ 168 @Override 169 public boolean containsAll(Collection<?> c) { 170 return lazy().containsAll(c); 171 } 172 173 /** 174 * Appends all of the elements in the specified collection to the end of 175 * this list, in the order that they are returned by the specified 176 * collection's iterator. 177 * 178 * @param c 179 * the collection containing elements to be added to this list. 180 * @return {@code true} if this list changed as a result of the call. 181 */ 182 @Override 183 public boolean addAll(Collection<? extends E> c) { 184 return lazy().addAll(c); 185 } 186 187 /** 188 * Inserts all of the elements in the specified collection into this list at 189 * the specified position. 190 * 191 * @param index 192 * the index at which to insert the first element from the 193 * specified collection. 194 * @param c 195 * the collection containing elements to be added to this list. 196 * @return {@code true} if this list changed as a result of the call. 197 */ 198 @Override 199 public boolean addAll(int index, Collection<? extends E> c) { 200 return lazy().addAll(index, c); 201 } 202 203 /** 204 * Removes from this list all of its elements that are contained in the 205 * specified collection. 206 * 207 * @param c 208 * the collection containing elements to be removed from this 209 * list. 210 * @return {@code true} if this list changed as a result of the call. 211 */ 212 @Override 213 public boolean removeAll(Collection<?> c) { 214 return lazy().removeAll(c); 215 } 216 217 /** 218 * Retains only the elements in this list that are contained in the 219 * specified collection. 220 * 221 * @param c 222 * the collection containing elements to be retained in this 223 * list. 224 * @return {@code true} if this list changed as a result of the call. 225 */ 226 @Override 227 public boolean retainAll(Collection<?> c) { 228 return lazy().retainAll(c); 229 } 230 231 /** 232 * Removes all of the elements from this list. 233 */ 234 @Override 235 public void clear() { 236 lazy().clear(); 237 } 238 239 /** 240 * Compares the specified object with this list for equality. 241 * 242 * @param o 243 * the object to be compared for equality with this list. 244 * @return {@code true} if the specified object is equal to this list. 245 */ 246 @Override 247 public boolean equals(Object o) { 248 return lazy().equals(o); 249 } 250 251 /** 252 * Returns the hash code value for this list. 253 */ 254 @Override 255 public int hashCode() { 256 return lazy().hashCode(); 257 } 258 259 /** 260 * Returns the element at the specified position in this list. 261 * 262 * @param index 263 * the index of the element to return. 264 * @return the element at the specified position in this list. 265 */ 266 @Override 267 public E get(int index) { 268 return lazy().get(index); 269 } 270 271 /** 272 * Replaces the element at the specified position in this list with the 273 * specified element. 274 * 275 * @param index 276 * the index of the element to replace. 277 * @param element 278 * the element to be stored at the specified position. 279 * @return the element previously at the specified position. 280 */ 281 @Override 282 public E set(int index, E element) { 283 return lazy().set(index, element); 284 } 285 286 /** 287 * Inserts the specified element at the specified position in this list. 288 * 289 * @param index 290 * the index at which the specified element is to be inserted. 291 * @param element 292 * the element to be inserted. 293 */ 294 @Override 295 public void add(int index, E element) { 296 lazy().add(index, element); 297 } 298 299 /** 300 * Removes the element at the specified position in this list. 301 * 302 * @param index 303 * the index of the element to be removed. 304 * @return the element previously at the specified position. 305 */ 306 @Override 307 public E remove(int index) { 308 return lazy().remove(index); 309 } 310 311 /** 312 * Returns the index of the first occurrence of the specified element in 313 * this list, or {@code -1} if this list does not contain the element. 314 * 315 * @param o 316 * element to search for. 317 * @return the index of the first occurrence, or {@code -1} if no such 318 * element. 319 */ 320 @Override 321 public int indexOf(Object o) { 322 return lazy().indexOf(o); 323 } 324 325 /** 326 * Returns the index of the last occurrence of the specified element in this 327 * list, or {@code -1} if this list does not contain the element. 328 * 329 * @param o 330 * the element to search for. 331 * @return the index of the last occurrence, or {@code -1} if no such 332 * element. 333 */ 334 @Override 335 public int lastIndexOf(Object o) { 336 return lazy().lastIndexOf(o); 337 } 338 339 /** 340 * Returns a list iterator over the elements in this list (in proper 341 * sequence). 342 */ 343 @Override 344 public ListIterator<E> listIterator() { 345 return lazy().listIterator(); 346 } 347 348 /** 349 * Returns a list iterator over the elements in this list (in proper 350 * sequence), starting at the specified position in the list. 351 * 352 * @param index 353 * the index of the first element to be returned from the list 354 * iterator. 355 * @return a list iterator, starting at the specified position in the list. 356 */ 357 @Override 358 public ListIterator<E> listIterator(int index) { 359 return lazy().listIterator(index); 360 } 361 362 /** 363 * Returns a view of the portion of this list between the specified 364 * fromIndex, inclusive, and toIndex, exclusive. 365 * 366 * @param fromIndex 367 * low endpoint (inclusive) of the subList. 368 * @param toIndex 369 * high endpoint (exclusive) of the subList. 370 * @return a view of the specified range within this list. 371 */ 372 @Override 373 public List<E> subList(int fromIndex, int toIndex) { 374 return lazy().subList(fromIndex, toIndex); 375 } 376 }