View Javadoc
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 }