/*
* 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.
*
* Created on March 26, 2003, 1:53 PM
*/
package org.geotools.feature;
import java.util.Iterator;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
/**
* The FeatureCollectionIteration provides a depth first traversal of a
* FeatureCollection<SimpleFeatureType, SimpleFeature> which will call the provided call-back Handler. Because
* of the complex nature of Features, which may have other Features (or even a
* collection of Features) as attributes, the handler is repsonsible for
* maintaining its own state as to where in the traversal it is recieving
* events from. Many handlers will not need to worry about state.
*
* <p>
* <b>Implementation Notes:</b> The depth first visitation is implemented
* through recursion. The limits to recursion depending on the settings in the
* JVM, but some tests show a 2 argument recursive having a limit of ~50000
* method calls with a stack size of 512k (the standard setting).
* </p>
*
* @author Ian Schneider, USDA-ARS
* @author Chris Holmes, TOPP
* @source $URL$
*/
public class FeatureCollectionIteration {
/**
* A callback handler for the iteration of the contents of a
* FeatureCollection.
*/
protected final Handler handler;
/** The collection being iterated */
private final FeatureCollection<SimpleFeatureType, SimpleFeature> collection;
/**
* Create a new FeatureCollectionIteration with the given handler and
* collection.
*
* @param handler The handler to perform operations on this iteration.
* @param collection The collection to iterate over.
*
* @throws NullPointerException If handler or collection are null.
*/
public FeatureCollectionIteration(Handler handler,
FeatureCollection<SimpleFeatureType, SimpleFeature> collection) throws NullPointerException {
if (handler == null) {
throw new NullPointerException("handler");
}
if (collection == null) {
throw new NullPointerException("collection");
}
this.handler = handler;
this.collection = collection;
}
/**
* A convienience method for obtaining a new iteration and calling iterate.
*
* @param handler The handler to perform operations on this iteration.
* @param collection The collection to iterate over.
*/
public static void iteration(Handler handler, FeatureCollection<SimpleFeatureType, SimpleFeature> collection) {
FeatureCollectionIteration iteration = new FeatureCollectionIteration(handler,
collection);
iteration.iterate();
}
/**
* Start the iteration.
*/
public void iterate() {
walker(collection);
}
/**
* Perform the iterative behavior on the given collection. This will alert
* the handler with a <code>handleFeatureCollection</code> call, followed
* by an <code> iterate()</code>, followed by a
* <code>handler.endFeatureCollection()</code> call.
*
* @param collection The collection to iterate upon.
*/
protected void walker(FeatureCollection<SimpleFeatureType, SimpleFeature> collection) {
handler.handleFeatureCollection(collection);
iterate(collection.iterator());
handler.endFeatureCollection(collection);
}
/**
* Perform the actual iteration on the Iterator which is provided.
*
* @param iterator The Iterator to iterate upon.
*/
protected void iterate(Iterator iterator) {
while (iterator.hasNext()) {
walker((SimpleFeature) iterator.next());
}
}
/**
* Perform the visitation of an individual Feature.
*
* @param feature The Feature to explore.
*/
protected void walker(SimpleFeature feature) {
final SimpleFeatureType schema = feature.getFeatureType();
final int cnt = schema.getAttributeCount();
handler.handleFeature(feature);
for (int i = 0; i < cnt; i++) {
AttributeDescriptor type = schema.getDescriptor(i);
// recurse if attribute type is another collection
if (FeatureCollection.class.isAssignableFrom(type.getType().getBinding())) {
walker((FeatureCollection<SimpleFeatureType, SimpleFeature>) feature.getAttribute(i));
// } else if (type instanceof FeatureType) {
} else if (SimpleFeature.class.isAssignableFrom(type.getType().getBinding())) {
// recurse if attribute type is another feature
walker((SimpleFeature) feature.getAttribute(i));
} else {
// normal handling
handler.handleAttribute(type, feature.getAttribute(i));
}
}
handler.endFeature(feature);
}
/**
* A callback handler for the iteration of the contents of a
* FeatureCollection.
*/
public interface Handler {
/**
* The handler is visiting a FeatureCollection.
*
* @param fc The currently visited FeatureCollection.
*/
void handleFeatureCollection(FeatureCollection<SimpleFeatureType, SimpleFeature> fc);
/**
* The handler is done visiting a FeatureCollection.
*
* @param fc The FeatureCollection<SimpleFeatureType, SimpleFeature> which was visited.
*/
void endFeatureCollection(FeatureCollection<SimpleFeatureType, SimpleFeature> fc);
/**
* The handler is visiting a Feature.
*
* @param f The Feature the handler is visiting.
*/
void handleFeature(SimpleFeature f);
/**
* The handler is ending its visit with a Feature.
*
* @param f The Feature that was visited.
*/
void endFeature(SimpleFeature f);
/**
* The handler is visiting an Attribute of a Feature.
*
* @param type The meta-data of the given attribute value.
* @param value The attribute value, may be null.
*/
void handleAttribute(AttributeDescriptor type, Object value);
}
}