001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the License. 004 * 005 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 006 * specific language governing permission and limitations under the License. 007 * 008 * When distributing Covered Software, include this CDDL Header Notice in each file and include 009 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 010 * Header, with the fields enclosed by brackets [] replaced by your own identifying 011 * information: "Portions copyright [year] [name of copyright owner]". 012 * 013 * Copyright 2015 ForgeRock AS. 014 */ 015 016package org.forgerock.util; 017 018// Java SE 019import java.util.Collection; 020import java.util.Iterator; 021import java.util.List; 022import java.util.ListIterator; 023 024/** 025 * A list with lazy initialization. The factory is called to initialize the list 026 * on the first call to one of this object's methods. 027 * 028 * @param <E> 029 * The type of element contained in this list. 030 */ 031public class LazyList<E> implements List<E> { 032 033 /** The list that this lazy list exposes, once initialized. */ 034 private List<E> list; 035 036 /** Factory to create the instance of the list to expose. */ 037 protected Factory<List<E>> factory; 038 039 /** 040 * Constructs a new lazy list. Allows factory to be set in subclass 041 * constructor. 042 */ 043 protected LazyList() { 044 } 045 046 /** 047 * Constructs a new lazy list. 048 * 049 * @param factory 050 * factory to create the list instance to expose. 051 */ 052 public LazyList(Factory<List<E>> factory) { 053 this.factory = factory; 054 } 055 056 /** 057 * Performs lazy initialization of the list if not already performed, and 058 * returns the initialized list. 059 */ 060 private List<E> lazy() { 061 if (list == null) { 062 synchronized (this) { 063 if (list == null) { 064 list = factory.newInstance(); 065 } 066 } 067 } 068 return list; 069 } 070 071 /** 072 * Returns the number of elements in this list. 073 */ 074 @Override 075 public int size() { 076 return lazy().size(); 077 } 078 079 /** 080 * Returns {@code true} if this list contains no elements. 081 */ 082 @Override 083 public boolean isEmpty() { 084 return lazy().isEmpty(); 085 } 086 087 /** 088 * Returns {@code true} if this list contains the specified element. 089 * 090 * @param o 091 * the element whose presence in this list is to be tested. 092 * @return {@code true} if this list contains the specified element. 093 */ 094 @Override 095 public boolean contains(Object o) { 096 return lazy().contains(o); 097 } 098 099 /** 100 * Returns an iterator over the elements in this list in proper sequence. 101 */ 102 @Override 103 public Iterator<E> iterator() { 104 return lazy().iterator(); 105 } 106 107 /** 108 * Returns an array containing all of the elements in this list in proper 109 * sequence (from first to last element). 110 */ 111 @Override 112 public Object[] toArray() { 113 return lazy().toArray(); 114 } 115 116 /** 117 * Returns an array containing all of the elements in this list in proper 118 * sequence (from first to last element); the runtime type of the returned 119 * array is that of the specified array. If the list fits in the specified 120 * array, it is returned therein. Otherwise, a new array is allocated with 121 * the runtime type of the specified array and the size of this list. 122 * 123 * @param a 124 * the array into which the elements of this list are to be 125 * stored. 126 * @return an array containing the elements of this list. 127 */ 128 @Override 129 public <T> T[] toArray(T[] a) { 130 return lazy().toArray(a); 131 } 132 133 /** 134 * Appends the specified element to the end of this list. 135 * 136 * @param e 137 * the element to be appended to this list. 138 * @return {@code true} if this list changed as a result of the call. 139 */ 140 @Override 141 public boolean add(E e) { 142 return lazy().add(e); 143 } 144 145 /** 146 * Removes the first occurrence of the specified element from this list, if 147 * it is present. 148 * 149 * @param o 150 * the element to be removed from this list, if present. 151 * @return true if this list contained the specified element. 152 */ 153 @Override 154 public boolean remove(Object o) { 155 return lazy().remove(o); 156 } 157 158 /** 159 * Returns {@code true} if this list contains all of the elements of the 160 * specified collection. 161 * 162 * @param c 163 * the collection to be checked for containment in this list. 164 * @return {@code true} if this list contains all of the elements of the 165 * specified collection. 166 */ 167 @Override 168 public boolean containsAll(Collection<?> c) { 169 return lazy().containsAll(c); 170 } 171 172 /** 173 * Appends all of the elements in the specified collection to the end of 174 * this list, in the order that they are returned by the specified 175 * collection's iterator. 176 * 177 * @param c 178 * the collection containing elements to be added to this list. 179 * @return {@code true} if this list changed as a result of the call. 180 */ 181 @Override 182 public boolean addAll(Collection<? extends E> c) { 183 return lazy().addAll(c); 184 } 185 186 /** 187 * Inserts all of the elements in the specified collection into this list at 188 * the specified position. 189 * 190 * @param index 191 * the index at which to insert the first element from the 192 * specified collection. 193 * @param c 194 * the collection containing elements to be added to this list. 195 * @return {@code true} if this list changed as a result of the call. 196 */ 197 @Override 198 public boolean addAll(int index, Collection<? extends E> c) { 199 return lazy().addAll(index, c); 200 } 201 202 /** 203 * Removes from this list all of its elements that are contained in the 204 * specified collection. 205 * 206 * @param c 207 * the collection containing elements to be removed from this 208 * list. 209 * @return {@code true} if this list changed as a result of the call. 210 */ 211 @Override 212 public boolean removeAll(Collection<?> c) { 213 return lazy().removeAll(c); 214 } 215 216 /** 217 * Retains only the elements in this list that are contained in the 218 * specified collection. 219 * 220 * @param c 221 * the collection containing elements to be retained in this 222 * list. 223 * @return {@code true} if this list changed as a result of the call. 224 */ 225 @Override 226 public boolean retainAll(Collection<?> c) { 227 return lazy().retainAll(c); 228 } 229 230 /** 231 * Removes all of the elements from this list. 232 */ 233 @Override 234 public void clear() { 235 lazy().clear(); 236 } 237 238 /** 239 * Compares the specified object with this list for equality. 240 * 241 * @param o 242 * the object to be compared for equality with this list. 243 * @return {@code true} if the specified object is equal to this list. 244 */ 245 @Override 246 public boolean equals(Object o) { 247 return lazy().equals(o); 248 } 249 250 /** 251 * Returns the hash code value for this list. 252 */ 253 @Override 254 public int hashCode() { 255 return lazy().hashCode(); 256 } 257 258 /** 259 * Returns the element at the specified position in this list. 260 * 261 * @param index 262 * the index of the element to return. 263 * @return the element at the specified position in this list. 264 */ 265 @Override 266 public E get(int index) { 267 return lazy().get(index); 268 } 269 270 /** 271 * Replaces the element at the specified position in this list with the 272 * specified element. 273 * 274 * @param index 275 * the index of the element to replace. 276 * @param element 277 * the element to be stored at the specified position. 278 * @return the element previously at the specified position. 279 */ 280 @Override 281 public E set(int index, E element) { 282 return lazy().set(index, element); 283 } 284 285 /** 286 * Inserts the specified element at the specified position in this list. 287 * 288 * @param index 289 * the index at which the specified element is to be inserted. 290 * @param element 291 * the element to be inserted. 292 */ 293 @Override 294 public void add(int index, E element) { 295 lazy().add(index, element); 296 } 297 298 /** 299 * Removes the element at the specified position in this list. 300 * 301 * @param index 302 * the index of the element to be removed. 303 * @return the element previously at the specified position. 304 */ 305 @Override 306 public E remove(int index) { 307 return lazy().remove(index); 308 } 309 310 /** 311 * Returns the index of the first occurrence of the specified element in 312 * this list, or {@code -1} if this list does not contain the element. 313 * 314 * @param o 315 * element to search for. 316 * @return the index of the first occurrence, or {@code -1} if no such 317 * element. 318 */ 319 @Override 320 public int indexOf(Object o) { 321 return lazy().indexOf(o); 322 } 323 324 /** 325 * Returns the index of the last occurrence of the specified element in this 326 * list, or {@code -1} if this list does not contain the element. 327 * 328 * @param o 329 * the element to search for. 330 * @return the index of the last occurrence, or {@code -1} if no such 331 * element. 332 */ 333 @Override 334 public int lastIndexOf(Object o) { 335 return lazy().lastIndexOf(o); 336 } 337 338 /** 339 * Returns a list iterator over the elements in this list (in proper 340 * sequence). 341 */ 342 @Override 343 public ListIterator<E> listIterator() { 344 return lazy().listIterator(); 345 } 346 347 /** 348 * Returns a list iterator over the elements in this list (in proper 349 * sequence), starting at the specified position in the list. 350 * 351 * @param index 352 * the index of the first element to be returned from the list 353 * iterator. 354 * @return a list iterator, starting at the specified position in the list. 355 */ 356 @Override 357 public ListIterator<E> listIterator(int index) { 358 return lazy().listIterator(index); 359 } 360 361 /** 362 * Returns a view of the portion of this list between the specified 363 * fromIndex, inclusive, and toIndex, exclusive. 364 * 365 * @param fromIndex 366 * low endpoint (inclusive) of the subList. 367 * @param toIndex 368 * high endpoint (exclusive) of the subList. 369 * @return a view of the specified range within this list. 370 */ 371 @Override 372 public List<E> subList(int fromIndex, int toIndex) { 373 return lazy().subList(fromIndex, toIndex); 374 } 375}