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.ListIterator;
020    import java.util.NoSuchElementException;
021    
022    import org.apache.commons.collections.ResettableListIterator;
023    
024    /**
025     * <code>SingletonIterator</code> is an {@link ListIterator} over a single 
026     * object instance.
027     *
028     * @since Commons Collections 2.1
029     * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
030     * 
031     * @author Stephen Colebourne
032     * @author Rodney Waldhoff
033     */
034    public class SingletonListIterator implements ListIterator, ResettableListIterator {
035    
036        private boolean beforeFirst = true;
037        private boolean nextCalled = false;
038        private boolean removed = false;
039        private Object object;
040    
041        /**
042         * Constructs a new <code>SingletonListIterator</code>.
043         *
044         * @param object  the single object to return from the iterator
045         */
046        public SingletonListIterator(Object object) {
047            super();
048            this.object = object;
049        }
050    
051        /**
052         * Is another object available from the iterator?
053         * <p>
054         * This returns true if the single object hasn't been returned yet.
055         * 
056         * @return true if the single object hasn't been returned yet
057         */
058        public boolean hasNext() {
059            return beforeFirst && !removed;
060        }
061    
062        /**
063         * Is a previous object available from the iterator?
064         * <p>
065         * This returns true if the single object has been returned.
066         * 
067         * @return true if the single object has been returned
068         */
069        public boolean hasPrevious() {
070            return !beforeFirst && !removed;
071        }
072    
073        /**
074         * Returns the index of the element that would be returned by a subsequent
075         * call to <tt>next</tt>.
076         *
077         * @return 0 or 1 depending on current state. 
078         */
079        public int nextIndex() {
080            return (beforeFirst ? 0 : 1);
081        }
082    
083        /**
084         * Returns the index of the element that would be returned by a subsequent
085         * call to <tt>previous</tt>. A return value of -1 indicates that the iterator is currently at
086         * the start.
087         *
088         * @return 0 or -1 depending on current state. 
089         */
090        public int previousIndex() {
091            return (beforeFirst ? -1 : 0);
092        }
093    
094        /**
095         * Get the next object from the iterator.
096         * <p>
097         * This returns the single object if it hasn't been returned yet.
098         *
099         * @return the single object
100         * @throws NoSuchElementException if the single object has already 
101         *    been returned
102         */
103        public Object next() {
104            if (!beforeFirst || removed) {
105                throw new NoSuchElementException();
106            }
107            beforeFirst = false;
108            nextCalled = true;
109            return object;
110        }
111    
112        /**
113         * Get the previous object from the iterator.
114         * <p>
115         * This returns the single object if it has been returned.
116         *
117         * @return the single object
118         * @throws NoSuchElementException if the single object has not already 
119         *    been returned
120         */
121        public Object previous() {
122            if (beforeFirst || removed) {
123                throw new NoSuchElementException();
124            }
125            beforeFirst = true;
126            return object;
127        }
128    
129        /**
130         * Remove the object from this iterator.
131         * @throws IllegalStateException if the <tt>next</tt> or <tt>previous</tt> 
132         *        method has not yet been called, or the <tt>remove</tt> method 
133         *        has already been called after the last call to <tt>next</tt>
134         *        or <tt>previous</tt>.
135         */
136        public void remove() {
137            if(!nextCalled || removed) {
138                throw new IllegalStateException();
139            } else {
140                object = null;
141                removed = true;
142            }
143        }
144        
145        /**
146         * Add always throws {@link UnsupportedOperationException}.
147         *
148         * @throws UnsupportedOperationException always
149         */
150        public void add(Object obj) {
151            throw new UnsupportedOperationException("add() is not supported by this iterator");
152        }
153        
154        /**
155         * Set sets the value of the singleton.
156         *
157         * @param obj  the object to set
158         * @throws IllegalStateException if <tt>next</tt> has not been called 
159         *          or the object has been removed
160         */
161        public void set(Object obj) {
162            if (!nextCalled || removed) {
163                throw new IllegalStateException();
164            }
165            this.object = obj;
166        }
167        
168        /**
169         * Reset the iterator back to the start.
170         */
171        public void reset() {
172            beforeFirst = true;
173            nextCalled = false;
174        }
175        
176    }