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.iterators;
018    
019    import java.util.ArrayList;
020    import java.util.Iterator;
021    import java.util.List;
022    import java.util.NoSuchElementException;
023    
024    import org.apache.commons.collections.ResettableListIterator;
025    
026    /**
027     * Converts an iterator into a list iterator by caching the returned entries.
028     * <p>
029     * The <code>ListIterator</code> interface has additional useful methods
030     * for navigation - <code>previous()</code> and the index methods.
031     * This class allows a regular <code>Iterator</code> to behave as a
032     * <code>ListIterator</code>. It achieves this by building a list internally
033     * of as the underlying iterator is traversed.
034     * <p>
035     * The optional operations of <code>ListIterator</code> are not supported.
036     * <p>
037     * This class implements ResettableListIterator from Commons Collections 3.2.
038     *
039     * @since Commons Collections 2.1
040     * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
041     *
042     * @author Morgan Delagrange
043     * @author Stephen Colebourne
044     */
045    public class ListIteratorWrapper implements ResettableListIterator {
046    
047        /** Message used when remove, set or add are called. */
048        private static final String UNSUPPORTED_OPERATION_MESSAGE =
049            "ListIteratorWrapper does not support optional operations of ListIterator.";
050    
051        /** The underlying iterator being decorated. */
052        private final Iterator iterator;
053        /** The list being used to cache the iterator. */
054        private final List list = new ArrayList();
055    
056        /** The current index of this iterator. */
057        private int currentIndex = 0;
058        /** The current index of the wrapped iterator. */
059        private int wrappedIteratorIndex = 0;
060    
061        // Constructor
062        //-------------------------------------------------------------------------
063        /**
064         * Constructs a new <code>ListIteratorWrapper</code> that will wrap
065         * the given iterator.
066         *
067         * @param iterator  the iterator to wrap
068         * @throws NullPointerException if the iterator is null
069         */
070        public ListIteratorWrapper(Iterator iterator) {
071            super();
072            if (iterator == null) {
073                throw new NullPointerException("Iterator must not be null");
074            }
075            this.iterator = iterator;
076        }
077    
078        // ListIterator interface
079        //-------------------------------------------------------------------------
080        /**
081         * Throws {@link UnsupportedOperationException}.
082         *
083         * @param obj  the object to add, ignored
084         * @throws UnsupportedOperationException always
085         */
086        public void add(Object obj) throws UnsupportedOperationException {
087            throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE);
088        }
089    
090        /**
091         * Returns true if there are more elements in the iterator.
092         *
093         * @return true if there are more elements
094         */
095        public boolean hasNext() {
096            if (currentIndex == wrappedIteratorIndex) {
097                return iterator.hasNext();
098            }
099            return true;
100        }
101    
102        /**
103         * Returns true if there are previous elements in the iterator.
104         *
105         * @return true if there are previous elements
106         */
107        public boolean hasPrevious() {
108            if (currentIndex == 0) {
109                return false;
110            }
111            return true;
112        }
113    
114        /**
115         * Returns the next element from the iterator.
116         *
117         * @return the next element from the iterator
118         * @throws NoSuchElementException if there are no more elements
119         */
120        public Object next() throws NoSuchElementException {
121            if (currentIndex < wrappedIteratorIndex) {
122                ++currentIndex;
123                return list.get(currentIndex - 1);
124            }
125    
126            Object retval = iterator.next();
127            list.add(retval);
128            ++currentIndex;
129            ++wrappedIteratorIndex;
130            return retval;
131        }
132    
133        /**
134         * Returns in the index of the next element.
135         *
136         * @return the index of the next element
137         */
138        public int nextIndex() {
139            return currentIndex;
140        }
141    
142        /**
143         * Returns the the previous element.
144         *
145         * @return the previous element
146         * @throws NoSuchElementException  if there are no previous elements
147         */
148        public Object previous() throws NoSuchElementException {
149            if (currentIndex == 0) {
150                throw new NoSuchElementException();
151            }
152            --currentIndex;
153            return list.get(currentIndex);    
154        }
155    
156        /**
157         * Returns the index of the previous element.
158         *
159         * @return  the index of the previous element
160         */
161        public int previousIndex() {
162            return currentIndex - 1;
163        }
164    
165        /**
166         * Throws {@link UnsupportedOperationException}.
167         *
168         * @throws UnsupportedOperationException always
169         */
170        public void remove() throws UnsupportedOperationException {
171            throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE);
172        }
173    
174        /**
175         * Throws {@link UnsupportedOperationException}.
176         *
177         * @param obj  the object to set, ignored
178         * @throws UnsupportedOperationException always
179         */
180        public void set(Object obj) throws UnsupportedOperationException {
181            throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE);
182        }
183    
184        // ResettableIterator interface
185        //-------------------------------------------------------------------------
186        /**
187         * Resets this iterator back to the position at which the iterator
188         * was created.
189         *
190         * @since Commons Collections 3.2
191         */
192        public void reset()  {
193            currentIndex = 0;
194        }
195    
196    }