/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2003-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.data; import java.io.IOException; import java.util.NoSuchElementException; import org.geotools.feature.IllegalAttributeException; import org.opengis.feature.Feature; import org.opengis.feature.type.FeatureType; import org.opengis.filter.Filter; /** * Basic support for a FeatureReader<SimpleFeatureType, SimpleFeature> that does filtering. I think that * filtering should perhaps be done in the AttributeReader. I'm still having * a bit of trouble with the split between attributeReader and featureReader * as to where the hooks for advanced processing like filtering should take * place. See my note on hasNext(), as the method is currently broken and * there are more optimizations that could take place if we had a * FilteringAttributeReader. So this class may go, but I thought I'd put the * ideas into code. * * <p> * Jody here - changed hasNext() to peek as required. * </p> * * @author Chris Holmes * * @source $URL$ * @version $Id$ */ public class FilteringFeatureReader<T extends FeatureType, F extends Feature> implements DelegatingFeatureReader<T,F> { protected final FeatureReader<T, F> featureReader; protected final Filter filter; protected F next; /** * Creates a new instance of AbstractFeatureReader * * <p> * Please don't call this method with Filter.INCLUDE or Filter.EXCLUDE (consider * not filtering and EmptyFeatureReader instead) * </p> * * @param featureReader FeatureReader<SimpleFeatureType, SimpleFeature> being filtered * @param filter Filter used to limit the results of featureReader */ public FilteringFeatureReader(FeatureReader<T, F> featureReader, Filter filter) { this.featureReader = featureReader; this.filter = filter; next = null; } /** * @return THe delegate reader. */ public FeatureReader<T, F> getDelegate() { return featureReader; } public F next() throws IOException, IllegalAttributeException, NoSuchElementException { F f = null; if (hasNext()) { // hasNext() ensures that next != null f = next; next = null; return f; } else { throw new NoSuchElementException("No such Feature exsists"); } } public void close() throws IOException { featureReader.close(); } public T getFeatureType() { return featureReader.getFeatureType(); } /** * Query for additional content. * * <p> * This class will peek ahead to see if there is additional content. * </p> * * <p> * Chris has pointed out that we could make use of AttributeReader based filtering:<br> * <i>"Also doing things in the Attribute Reader would allow us to do the * smart filtering, only looking at the attributes needed for comparison, * whereas doing filtering here means we have to create an entire feature * each time."</i> * </p> * * @return <code>true</code> if we have additional content * * @throws IOException If the reader we are filtering encounters a problem * @throws DataSourceException See IOException */ public boolean hasNext() throws IOException { if (next != null) { return true; } try { F peek; while (featureReader.hasNext()) { peek = featureReader.next(); if (filter.evaluate(peek)) { next = peek; return true; } } } catch (IllegalAttributeException e) { throw new DataSourceException("Could not peek ahead", e); } return next != null; } }