001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.commons.collections.list;
018    
019    import java.util.List;
020    
021    import org.apache.commons.collections.Factory;
022    
023    /**
024     * Decorates another <code>List</code> to create objects in the list on demand.
025     * <p>
026     * When the {@link #get(int)} method is called with an index greater than
027     * the size of the list, the list will automatically grow in size and return
028     * a new object from the specified factory. The gaps will be filled by null.
029     * If a get method call encounters a null, it will be replaced with a new
030     * object from the factory. Thus this list is unsuitable for storing null
031     * objects.
032     * <p>
033     * For instance:
034     *
035     * <pre>
036     * Factory factory = new Factory() {
037     *     public Object create() {
038     *         return new Date();
039     *     }
040     * }
041     * List lazy = LazyList.decorate(new ArrayList(), factory);
042     * Object obj = lazy.get(3);
043     * </pre>
044     *
045     * After the above code is executed, <code>obj</code> will contain
046     * a new <code>Date</code> instance.  Furthermore, that <code>Date</code>
047     * instance is the fourth element in the list.  The first, second, 
048     * and third element are all set to <code>null</code>.
049     * <p>
050     * This class differs from {@link GrowthList} because here growth occurs on
051     * get, where <code>GrowthList</code> grows on set and add. However, they
052     * could easily be used together by decorating twice.
053     * <p>
054     * This class is Serializable from Commons Collections 3.1.
055     *
056     * @see GrowthList
057     * @since Commons Collections 3.0
058     * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
059     * 
060     * @author Stephen Colebourne
061     * @author Arron Bates
062     * @author Paul Jack
063     */
064    public class LazyList extends AbstractSerializableListDecorator {
065    
066        /** Serialization version */
067        private static final long serialVersionUID = -1708388017160694542L;
068    
069        /** The factory to use to lazily instantiate the objects */
070        protected final Factory factory;
071    
072        /**
073         * Factory method to create a lazily instantiating list.
074         * 
075         * @param list  the list to decorate, must not be null
076         * @param factory  the factory to use for creation, must not be null
077         * @throws IllegalArgumentException if list or factory is null
078         */
079        public static List decorate(List list, Factory factory) {
080            return new LazyList(list, factory);
081        }
082        
083        //-----------------------------------------------------------------------
084        /**
085         * Constructor that wraps (not copies).
086         * 
087         * @param list  the list to decorate, must not be null
088         * @param factory  the factory to use for creation, must not be null
089         * @throws IllegalArgumentException if list or factory is null
090         */
091        protected LazyList(List list, Factory factory) {
092            super(list);
093            if (factory == null) {
094                throw new IllegalArgumentException("Factory must not be null");
095            }
096            this.factory = factory;
097        }
098    
099        //-----------------------------------------------------------------------
100        /**
101         * Decorate the get method to perform the lazy behaviour.
102         * <p>
103         * If the requested index is greater than the current size, the list will 
104         * grow to the new size and a new object will be returned from the factory.
105         * Indexes in-between the old size and the requested size are left with a 
106         * placeholder that is replaced with a factory object when requested.
107         * 
108         * @param index  the index to retrieve
109         */
110        public Object get(int index) {
111            int size = getList().size();
112            if (index < size) {
113                // within bounds, get the object
114                Object object = getList().get(index);
115                if (object == null) {
116                    // item is a place holder, create new one, set and return
117                    object = factory.create();
118                    getList().set(index, object);
119                    return object;
120                } else {
121                    // good and ready to go
122                    return object;
123                }
124            } else {
125                // we have to grow the list
126                for (int i = size; i < index; i++) {
127                    getList().add(null);
128                }
129                // create our last object, set and return
130                Object object = factory.create();
131                getList().add(object);
132                return object;
133            }
134        }
135    
136    
137        public List subList(int fromIndex, int toIndex) {
138            List sub = getList().subList(fromIndex, toIndex);
139            return new LazyList(sub, factory);
140        }
141    
142    }