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 }