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 }