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.Predicate;
023
024 /**
025 * Decorates another {@link ListIterator} 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 2.0
031 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
032 *
033 * @author Rodney Waldhoff
034 */
035 public class FilterListIterator implements ListIterator {
036
037 /** The iterator being used */
038 private ListIterator iterator;
039
040 /** The predicate being used */
041 private Predicate predicate;
042
043 /**
044 * The value of the next (matching) object, when
045 * {@link #nextObjectSet} is true.
046 */
047 private Object nextObject;
048
049 /**
050 * Whether or not the {@link #nextObject} has been set
051 * (possibly to <code>null</code>).
052 */
053 private boolean nextObjectSet = false;
054
055 /**
056 * The value of the previous (matching) object, when
057 * {@link #previousObjectSet} is true.
058 */
059 private Object previousObject;
060
061 /**
062 * Whether or not the {@link #previousObject} has been set
063 * (possibly to <code>null</code>).
064 */
065 private boolean previousObjectSet = false;
066
067 /**
068 * The index of the element that would be returned by {@link #next}.
069 */
070 private int nextIndex = 0;
071
072 //-----------------------------------------------------------------------
073 /**
074 * Constructs a new <code>FilterListIterator</code> that will not function
075 * until {@link #setListIterator(ListIterator) setListIterator}
076 * and {@link #setPredicate(Predicate) setPredicate} are invoked.
077 */
078 public FilterListIterator() {
079 super();
080 }
081
082 /**
083 * Constructs a new <code>FilterListIterator</code> that will not
084 * function until {@link #setPredicate(Predicate) setPredicate} is invoked.
085 *
086 * @param iterator the iterator to use
087 */
088 public FilterListIterator(ListIterator iterator ) {
089 super();
090 this.iterator = iterator;
091 }
092
093 /**
094 * Constructs a new <code>FilterListIterator</code>.
095 *
096 * @param iterator the iterator to use
097 * @param predicate the predicate to use
098 */
099 public FilterListIterator(ListIterator iterator, Predicate predicate) {
100 super();
101 this.iterator = iterator;
102 this.predicate = predicate;
103 }
104
105 /**
106 * Constructs a new <code>FilterListIterator</code> that will not function
107 * until {@link #setListIterator(ListIterator) setListIterator} is invoked.
108 *
109 * @param predicate the predicate to use.
110 */
111 public FilterListIterator(Predicate predicate) {
112 super();
113 this.predicate = predicate;
114 }
115
116 //-----------------------------------------------------------------------
117 /** Not supported. */
118 public void add(Object o) {
119 throw new UnsupportedOperationException("FilterListIterator.add(Object) is not supported.");
120 }
121
122 public boolean hasNext() {
123 if(nextObjectSet) {
124 return true;
125 } else {
126 return setNextObject();
127 }
128 }
129
130 public boolean hasPrevious() {
131 if(previousObjectSet) {
132 return true;
133 } else {
134 return setPreviousObject();
135 }
136 }
137
138 public Object next() {
139 if(!nextObjectSet) {
140 if(!setNextObject()) {
141 throw new NoSuchElementException();
142 }
143 }
144 nextIndex++;
145 Object temp = nextObject;
146 clearNextObject();
147 return temp;
148 }
149
150 public int nextIndex() {
151 return nextIndex;
152 }
153
154 public Object previous() {
155 if(!previousObjectSet) {
156 if(!setPreviousObject()) {
157 throw new NoSuchElementException();
158 }
159 }
160 nextIndex--;
161 Object temp = previousObject;
162 clearPreviousObject();
163 return temp;
164 }
165
166 public int previousIndex() {
167 return (nextIndex-1);
168 }
169
170 /** Not supported. */
171 public void remove() {
172 throw new UnsupportedOperationException("FilterListIterator.remove() is not supported.");
173 }
174
175 /** Not supported. */
176 public void set(Object o) {
177 throw new UnsupportedOperationException("FilterListIterator.set(Object) is not supported.");
178 }
179
180 //-----------------------------------------------------------------------
181 /**
182 * Gets the iterator this iterator is using.
183 *
184 * @return the iterator.
185 */
186 public ListIterator getListIterator() {
187 return iterator;
188 }
189
190 /**
191 * Sets the iterator for this iterator to use.
192 * If iteration has started, this effectively resets the iterator.
193 *
194 * @param iterator the iterator to use
195 */
196 public void setListIterator(ListIterator iterator) {
197 this.iterator = iterator;
198 }
199
200 //-----------------------------------------------------------------------
201 /**
202 * Gets the predicate this iterator is using.
203 *
204 * @return the predicate.
205 */
206 public Predicate getPredicate() {
207 return predicate;
208 }
209
210 /**
211 * Sets the predicate this the iterator to use.
212 *
213 * @param predicate the transformer to use
214 */
215 public void setPredicate(Predicate predicate) {
216 this.predicate = predicate;
217 }
218
219 //-----------------------------------------------------------------------
220 private void clearNextObject() {
221 nextObject = null;
222 nextObjectSet = false;
223 }
224
225 private boolean setNextObject() {
226 // if previousObjectSet,
227 // then we've walked back one step in the
228 // underlying list (due to a hasPrevious() call)
229 // so skip ahead one matching object
230 if(previousObjectSet) {
231 clearPreviousObject();
232 if(!setNextObject()) {
233 return false;
234 } else {
235 clearNextObject();
236 }
237 }
238
239 while(iterator.hasNext()) {
240 Object object = iterator.next();
241 if(predicate.evaluate(object)) {
242 nextObject = object;
243 nextObjectSet = true;
244 return true;
245 }
246 }
247 return false;
248 }
249
250 private void clearPreviousObject() {
251 previousObject = null;
252 previousObjectSet = false;
253 }
254
255 private boolean setPreviousObject() {
256 // if nextObjectSet,
257 // then we've walked back one step in the
258 // underlying list (due to a hasNext() call)
259 // so skip ahead one matching object
260 if(nextObjectSet) {
261 clearNextObject();
262 if(!setPreviousObject()) {
263 return false;
264 } else {
265 clearPreviousObject();
266 }
267 }
268
269 while(iterator.hasPrevious()) {
270 Object object = iterator.previous();
271 if(predicate.evaluate(object)) {
272 previousObject = object;
273 previousObjectSet = true;
274 return true;
275 }
276 }
277 return false;
278 }
279
280 }