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.Iterator;
020    import java.util.NoSuchElementException;
021    
022    import org.apache.commons.collections.Predicate;
023    
024    /** 
025     * Decorates another {@link Iterator} using a predicate to filter elements.
026     * <p>
027     * This iterator decorates the underlying iterator, only allowing through
028     * those elements that match the specified {@link Predicate Predicate}.
029     *
030     * @since Commons Collections 1.0
031     * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
032     * 
033     * @author James Strachan
034     * @author Jan Sorensen
035     * @author Ralph Wagner
036     * @author Stephen Colebourne
037     */
038    public class FilterIterator implements Iterator {
039    
040        /** The iterator being used */
041        private Iterator iterator;
042        /** The predicate being used */
043        private Predicate predicate;
044        /** The next object in the iteration */
045        private Object nextObject;
046        /** Whether the next object has been calculated yet */
047        private boolean nextObjectSet = false;
048    
049        //-----------------------------------------------------------------------
050        /**
051         * Constructs a new <code>FilterIterator</code> that will not function
052         * until {@link #setIterator(Iterator) setIterator} is invoked.
053         */
054        public FilterIterator() {
055            super();
056        }
057    
058        /**
059         * Constructs a new <code>FilterIterator</code> that will not function
060         * until {@link #setPredicate(Predicate) setPredicate} is invoked.
061         *
062         * @param iterator  the iterator to use
063         */
064        public FilterIterator(Iterator iterator) {
065            super();
066            this.iterator = iterator;
067        }
068    
069        /**
070         * Constructs a new <code>FilterIterator</code> that will use the
071         * given iterator and predicate.
072         *
073         * @param iterator  the iterator to use
074         * @param predicate  the predicate to use
075         */
076        public FilterIterator(Iterator iterator, Predicate predicate) {
077            super();
078            this.iterator = iterator;
079            this.predicate = predicate;
080        }
081    
082        //-----------------------------------------------------------------------
083        /** 
084         * Returns true if the underlying iterator contains an object that 
085         * matches the predicate.
086         *
087         * @return true if there is another object that matches the predicate
088         * @throws NullPointerException if either the iterator or predicate are null
089         */
090        public boolean hasNext() {
091            if (nextObjectSet) {
092                return true;
093            } else {
094                return setNextObject();
095            }
096        }
097    
098        /** 
099         * Returns the next object that matches the predicate.
100         *
101         * @return the next object which matches the given predicate
102         * @throws NullPointerException if either the iterator or predicate are null
103         * @throws NoSuchElementException if there are no more elements that
104         *  match the predicate 
105         */
106        public Object next() {
107            if (!nextObjectSet) {
108                if (!setNextObject()) {
109                    throw new NoSuchElementException();
110                }
111            }
112            nextObjectSet = false;
113            return nextObject;
114        }
115    
116        /**
117         * Removes from the underlying collection of the base iterator the last
118         * element returned by this iterator.
119         * This method can only be called
120         * if <code>next()</code> was called, but not after
121         * <code>hasNext()</code>, because the <code>hasNext()</code> call
122         * changes the base iterator.
123         *
124         * @throws IllegalStateException if <code>hasNext()</code> has already
125         *  been called.
126         */
127        public void remove() {
128            if (nextObjectSet) {
129                throw new IllegalStateException("remove() cannot be called");
130            }
131            iterator.remove();
132        }
133    
134        //-----------------------------------------------------------------------
135        /** 
136         * Gets the iterator this iterator is using.
137         *
138         * @return the iterator
139         */
140        public Iterator getIterator() {
141            return iterator;
142        }
143    
144        /** 
145         * Sets the iterator for this iterator to use.
146         * If iteration has started, this effectively resets the iterator.
147         *
148         * @param iterator  the iterator to use
149         */
150        public void setIterator(Iterator iterator) {
151            this.iterator = iterator;
152            nextObject = null;
153            nextObjectSet = false;
154        }
155    
156        //-----------------------------------------------------------------------
157        /** 
158         * Gets the predicate this iterator is using.
159         *
160         * @return the predicate
161         */
162        public Predicate getPredicate() {
163            return predicate;
164        }
165    
166        /** 
167         * Sets the predicate this the iterator to use.
168         *
169         * @param predicate  the predicate to use
170         */
171        public void setPredicate(Predicate predicate) {
172            this.predicate = predicate;
173            nextObject = null;
174            nextObjectSet = false;
175        }
176    
177        //-----------------------------------------------------------------------
178        /**
179         * Set nextObject to the next object. If there are no more 
180         * objects then return false. Otherwise, return true.
181         */
182        private boolean setNextObject() {
183            while (iterator.hasNext()) {
184                Object object = iterator.next();
185                if (predicate.evaluate(object)) {
186                    nextObject = object;
187                    nextObjectSet = true;
188                    return true;
189                }
190            }
191            return false;
192        }
193    
194    }