Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First round of bug fixes including addition of BaseFeatureCollection …

…as a replacement for AbstractFeatureCollection that just needs features() method
  • Loading branch information...
commit 3375ba190b75a0424d235794bd3eac799b9a4fd6 1 parent ca57795
@jodygarnett jodygarnett authored
View
2  modules/library/main/src/main/java/org/geotools/data/CollectionFeatureReader.java
@@ -104,7 +104,7 @@ public SimpleFeature next()
* @see org.geotools.data.FeatureReader#hasNext()
*/
public boolean hasNext() throws IOException {
- return features.hasNext() && !closed;
+ return features != null && features.hasNext() && !closed;
}
/**
View
6 modules/library/main/src/main/java/org/geotools/data/DataTestCase.java
@@ -68,9 +68,9 @@
protected SimpleFeature[] roadFeatures;
protected ReferencedEnvelope roadBounds;
protected ReferencedEnvelope rd12Bounds;
- protected Filter rd1Filter;
- protected Filter rd2Filter;
- protected Filter rd12Filter;
+ protected Id rd1Filter;
+ protected Id rd2Filter;
+ protected Id rd12Filter;
protected SimpleFeature newRoad;
protected SimpleFeatureType riverType; // river: id, geom, river, flow
View
2  modules/library/main/src/main/java/org/geotools/data/store/ReprojectingFeatureCollection.java
@@ -143,7 +143,7 @@ private SimpleFeatureType reType(SimpleFeatureType type,
public SimpleFeatureIterator features() {
try {
- return new ReprojectingFeatureIterator(features(), transform, schema, transformer);
+ return new ReprojectingFeatureIterator(delegate.features(), transform, schema, transformer);
} catch (Exception e) {
throw new RuntimeException(e);
}
View
34 modules/library/main/src/main/java/org/geotools/feature/collection/AbstractFeatureCollection.java
@@ -2,7 +2,7 @@
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
- * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo)
+ * (C) 2003-2012, 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
@@ -30,10 +30,23 @@
import org.opengis.filter.sort.SortBy;
/**
- * Implement a feature collection just based on provision of iterator.
+ * Implement a feature collection just based on provision of an {@link Iterator}.
+ * <p>
+ * This implementation asks you to implement:
+ * <ul>
+ * <li>{@link #openIterator()}</li>
+ * <li>{@link #size()}</li>
+ * <li>
+ * User interaction is provided by the public API for FeatureCollection:
+ * <ul>
+ * <li>{@link #features()}: makes use of {@link DelegateSimpleFeatureIterator} (if needed) to wrap your iterator up as a SimpleFeatureIterator for
+ * public use.</li>
+ * </ul>
+ * This is the origional implementation of FeatureCollection and is recommended
+ * when presenting {@link Collection} classes as a FeatureCollection.
+ *
+ * @author Jody Garnett (LISAsoft)
*
- * @author Jody Garnett (Refractions Research Inc)
- *
* @source $URL$
*/
public abstract class AbstractFeatureCollection implements SimpleFeatureCollection {
@@ -51,14 +64,13 @@ protected AbstractFeatureCollection(SimpleFeatureType memberType) {
//
// SimpleFeatureCollection - Feature Access
//
- public SimpleFeatureIterator features() {
+ public SimpleFeatureIterator features() {
Iterator<SimpleFeature> iterator = openIterator();
- if( iterator instanceof SimpleFeatureIterator ){
- return (SimpleFeatureIterator) iterator;
- }
- else {
- SimpleFeatureIterator iter = new DelegateSimpleFeatureIterator( this, iterator );
- return iter;
+ if (iterator instanceof SimpleFeatureIterator) {
+ return (SimpleFeatureIterator) iterator;
+ } else {
+ SimpleFeatureIterator iter = new DelegateSimpleFeatureIterator(this, iterator);
+ return iter;
}
}
View
279 modules/library/main/src/main/java/org/geotools/feature/collection/BaseFeatureCollection.java
@@ -0,0 +1,279 @@
+/*
+ * GeoTools - The Open Source Java GIS Toolkit
+ * http://geotools.org
+ *
+ * (C) 2005-2012, 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.feature.collection;
+
+import java.util.Collection;
+
+import org.geotools.data.simple.SimpleFeatureCollection;
+import org.geotools.data.simple.SimpleFeatureIterator;
+import org.geotools.data.store.EmptyFeatureCollection;
+import org.geotools.feature.FeatureIterator;
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.geotools.util.NullProgressListener;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.filter.Filter;
+import org.opengis.filter.sort.SortBy;
+import org.opengis.geometry.BoundingBox;
+
+/**
+ * Implement a feature collection just based on provision of a {@link FeatureIterator}.
+ * <p>
+ * This implementation asks you to implement:
+ * <ul>
+ * <li>{@link #features()}</li>
+ * <li>
+ * This is the direct decentent of the origional {@link AbstractFeatureCollection}
+ * and represents the easiest way to package your content as a SimpleFeatureCollection
+ * (with no optimisation).
+ * <p>
+ * As this class provides no optimization, it is strongly recommended that you implement
+ * the following methods (which require a whole collection traversal):
+ * <ul>
+ * <li>{@link #size()}</li>
+ * <li>{@link #getBounds()</li>
+ * </ul>
+ *
+ * @author Jody Garnett (LISAsoft)
+ * @source $URL$
+ */
+public abstract class BaseFeatureCollection implements SimpleFeatureCollection {
+ /**
+ * id used when serialized to gml
+ */
+ protected String id;
+ protected SimpleFeatureType schema;
+
+ protected BaseFeatureCollection(SimpleFeatureType schema) {
+ this.id = id == null ? "featureCollection" : id;
+ this.schema = schema;
+ }
+
+ public String getID() {
+ return id;
+ }
+
+ public SimpleFeatureType getSchema() {
+ return schema;
+ }
+
+ //
+ // SimpleFeatureCollection - Feature Access
+ //
+ /**
+ * Subclasses required to implement this method to traverse FeatureCollection contents.
+ * <p>
+ * Note that {@link SimpleFeatureIterator#close()} is available to clean up
+ * after any resource use required during traversal.
+ */
+ public abstract SimpleFeatureIterator features();
+
+ /**
+ * Returns <tt>true</tt> if this collection contains the specified element. <tt></tt>.
+ * <p>
+ *
+ * This implementation iterates over the elements in the collection, checking each element in turn for equality with the specified element.
+ *
+ * @param o object to be checked for containment in this collection.
+ * @return <tt>true</tt> if this collection contains the specified element.
+ */
+ public boolean contains(Object o) {
+ SimpleFeatureIterator e = features();
+ try {
+ if (o == null) {
+ while (e.hasNext()){
+ if (e.next() == null){
+ return true;
+ }
+ }
+ } else {
+ while (e.hasNext()){
+ if (o.equals(e.next())){
+ return true;
+ }
+ }
+ }
+ return false;
+ } finally {
+ e.close();
+ }
+ }
+
+ /**
+ * Returns <tt>true</tt> if this collection contains all of the elements in the specified collection.
+ * <p>
+ *
+ * @param c collection to be checked for containment in this collection.
+ * @return <tt>true</tt> if this collection contains all of the elements in the specified collection.
+ * @throws NullPointerException if the specified collection is null.
+ *
+ * @see #contains(Object)
+ */
+ public boolean containsAll(Collection<?> c) {
+ SimpleFeatureIterator e = features();
+ try {
+ while (e.hasNext()){
+ SimpleFeature feature = e.next();
+ if (!c.contains(feature)){
+ return false;
+ }
+ }
+ return true;
+ } finally {
+ e.close();
+ }
+ }
+
+ /**
+ * @return <tt>true</tt> if this collection contains no elements.
+ */
+ public boolean isEmpty() {
+ SimpleFeatureIterator iterator = features();
+ try {
+ return !iterator.hasNext();
+ } finally {
+ iterator.close();
+ }
+ }
+
+ /**
+ * Array of all the elements.
+ *
+ * @return an array containing all of the elements in this collection.
+ */
+ public Object[] toArray() {
+ Object[] result = new Object[size()];
+ SimpleFeatureIterator e = null;
+ try {
+ e = features();
+ for (int i = 0; e.hasNext(); i++)
+ result[i] = e.next();
+ return result;
+ } finally {
+ e.close();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public <O> O[] toArray(O[] a) {
+ int size = size();
+ if (a.length < size) {
+ a = (O[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
+ }
+ SimpleFeatureIterator it = features();
+ try {
+ Object[] result = a;
+ for (int i = 0; i < size; i++)
+ result[i] = it.next();
+ if (a.length > size)
+ a[size] = null;
+ return a;
+ } finally {
+ it.close();
+ }
+ }
+
+ public void accepts(org.opengis.feature.FeatureVisitor visitor,
+ org.opengis.util.ProgressListener progress) {
+ SimpleFeatureIterator iterator = null;
+ if (progress == null)
+ progress = new NullProgressListener();
+ try {
+ float size = size();
+ float position = 0;
+ progress.started();
+ for (iterator = features(); !progress.isCanceled() && iterator.hasNext();) {
+ if (size > 0)
+ progress.progress(position++ / size);
+ try {
+ SimpleFeature feature = (SimpleFeature) iterator.next();
+ visitor.visit(feature);
+ } catch (Exception erp) {
+ progress.exceptionOccurred(erp);
+ }
+ }
+ } finally {
+ progress.complete();
+ iterator.close();
+ }
+ }
+
+ //
+ // Feature Collections API
+ //
+ public SimpleFeatureCollection subCollection(Filter filter) {
+ if (filter == Filter.INCLUDE) {
+ return this;
+ }
+ if( filter == Filter.EXCLUDE) {
+ return new EmptyFeatureCollection(schema);
+ }
+ return new SubFeatureCollection(this, filter);
+ }
+
+ public SimpleFeatureCollection sort(SortBy order) {
+ return new SubFeatureList(this, order);
+ }
+
+ /**
+ * Returns the number of elements in this collection.
+ *
+ * @return Number of items, or Interger.MAX_VALUE
+ */
+ public int size(){
+ int count = 0;
+ SimpleFeatureIterator it = features();
+ try {
+ while( it.hasNext() ){
+ @SuppressWarnings("unused")
+ SimpleFeature feature = it.next();
+ count++;
+ }
+ } finally {
+ it.close();
+ }
+ return count;
+ }
+
+ /**
+ * Full collection traversal to obtain bounds of FeatureCollection.
+ * Subclasees are strong encouraged to override this expensive method
+ * (even if just to implement caching).
+ */
+ public ReferencedEnvelope getBounds(){
+ ReferencedEnvelope bounds = null;
+ SimpleFeatureIterator it = features();
+ try {
+ while( it.hasNext() ){
+ SimpleFeature feature = it.next();
+ BoundingBox bbox = feature.getBounds();
+ if( bbox != null ){
+ if( bounds == null ){
+ bounds = new ReferencedEnvelope( bbox );
+ }
+ else {
+ bounds.include( bbox );
+ }
+ }
+ }
+ } finally {
+ it.close();
+ }
+ return bounds;
+ }
+
+}
View
6 modules/library/main/src/main/java/org/geotools/feature/collection/DecoratingFeatureCollection.java
@@ -16,11 +16,8 @@
*/
package org.geotools.feature.collection;
-import java.io.IOException;
import java.util.Collection;
-import java.util.Iterator;
-import org.geotools.feature.CollectionListener;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.jts.ReferencedEnvelope;
@@ -38,9 +35,6 @@
* @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
* @since 2.5
*
- *
- *
- *
* @source $URL$
*/
public class DecoratingFeatureCollection<T extends FeatureType, F extends Feature> implements
View
156 modules/library/main/src/main/java/org/geotools/feature/collection/SubFeatureCollection.java
@@ -16,14 +16,19 @@
*/
package org.geotools.feature.collection;
+import java.io.Closeable;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import org.geotools.data.FeatureReader;
import org.geotools.data.collection.DelegateFeatureReader;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
+import org.geotools.data.simple.SimpleFeatureSource;
+import org.geotools.data.store.FilteringFeatureIterator;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.visitor.BoundsVisitor;
@@ -36,40 +41,38 @@
import org.opengis.filter.sort.SortBy;
/**
- * Used as a reasonable default implementation for subCollection.
+ * Reasonable default implementation for subCollection making
+ * use of parent {@link SimpleFeatureCollection#features()}
+ * and provided Fitler.
* <p>
- * Note: to implementors, this is not optimal, please do your own
- * thing - your users will thank you.
- * </p>
+ * This is only a reasonable implementation and is not optimal. It is recommended
+ * that implementors construct a new {@link Query} and use {@link SimpleFeatureSource#getFeatures(Query)}.
*
* @author Jody Garnett, Refractions Research, Inc.
- *
- *
- *
* @source $URL$
*/
-public class SubFeatureCollection extends AbstractFeatureCollection {
+public class SubFeatureCollection extends BaseFeatureCollection {
/** Filter */
protected Filter filter;
/** Original Collection */
- protected SimpleFeatureCollection collection;
-
- protected FilterFactory ff = CommonFactoryFinder.getFilterFactory( null );
+ protected SimpleFeatureCollection collection;
+ protected FilterFactory ff = CommonFactoryFinder.getFilterFactory();
- public SubFeatureCollection(SimpleFeatureCollection collection ) {
+ public SubFeatureCollection(SimpleFeatureCollection collection) {
this( collection, Filter.INCLUDE );
}
-
/**
* @param collection Collection or AbstractFeatureCollection
* @param subfilter
*/
public SubFeatureCollection(SimpleFeatureCollection collection, Filter subfilter) {
- super(collection.getSchema());
- if (subfilter == null)
+ super( collection.getSchema() );
+
+ if (subfilter == null){
subfilter = Filter.INCLUDE;
+ }
if (subfilter.equals(Filter.EXCLUDE)) {
throw new IllegalArgumentException("A subcollection with Filter.EXCLUDE would be empty");
}
@@ -82,51 +85,37 @@ public SubFeatureCollection(SimpleFeatureCollection collection, Filter subfilter
this.collection = filtered.collection;
this.filter = ff.and(filtered.filter(), subfilter);
}
- } else if (collection instanceof Collection
- || collection instanceof AbstractFeatureCollection
- || collection instanceof AdaptorFeatureCollection) {
+ } else {
this.collection = collection;
this.filter = subfilter;
}
- else {
- throw new IllegalArgumentException("collection supports java.util.Collection or AbstractFeatureCollection");
- }
}
- @SuppressWarnings("unchecked")
- public Iterator<SimpleFeature> openIterator() {
- if (collection instanceof Collection) {
- Iterator<SimpleFeature> it = ((Collection<SimpleFeature>) collection).iterator();
- return new FilteredIterator<SimpleFeature>(it, filter());
- } else if (collection instanceof AbstractFeatureCollection) {
- Iterator<SimpleFeature> iterator = ((AbstractFeatureCollection) collection).iterator();
- return new FilteredIterator<SimpleFeature>(iterator, filter());
- } else if (collection instanceof AbstractFeatureCollection) {
- Iterator<SimpleFeature> iterator = ((AdaptorFeatureCollection) collection).iterator();
- return new FilteredIterator<SimpleFeature>(iterator, filter());
- } else {
- // JG because we have an implementation of features we should
- // choose a different base class that does not require an Iterator
- throw new UnsupportedOperationException();
- }
+ public SimpleFeatureIterator features() {
+ return new FilteringFeatureIterator( collection.features(), filter());
}
- public int size() {
- int count = 0;
- Iterator<SimpleFeature> i = null;
- try {
- for( i = iterator(); i.hasNext(); count++) i.next();
- }
- finally {
- if( i instanceof FeatureIterator){
- ((FeatureIterator<?>)i).close();
- }
- }
- return count;
- }
-
- protected Filter filter(){
- if( filter == null ){
+ public int size() {
+ int count = 0;
+ SimpleFeatureIterator i = features();
+ try {
+ while (i.hasNext()) {
+ i.next();
+ count++;
+ }
+ } finally {
+ i.close();
+ }
+ return count;
+ }
+ /**
+ * Generate filter to use for content, makes use of {@link #createFilter()}
+ * if needed.
+ *
+ * @return Filter to use for content
+ */
+ protected Filter filter() {
+ if (filter == null) {
filter = createFilter();
}
return filter;
@@ -136,50 +125,40 @@ protected Filter filter(){
protected Filter createFilter(){
return Filter.INCLUDE;
}
-
- public SimpleFeatureIterator features() {
- return new DelegateSimpleFeatureIterator( this, iterator() );
- }
-
-
- public void close(SimpleFeatureIterator close) {
- if( close != null ) close.close();
- }
-
//
//
//
- public SimpleFeatureCollection subCollection(Filter filter) {
- if (filter.equals(Filter.INCLUDE)) {
- return this;
- }
- if (filter.equals(Filter.EXCLUDE)) {
- // TODO implement EmptyFeatureCollection( schema )
- }
- return new SubFeatureCollection(this, filter);
- }
+ public SimpleFeatureCollection subCollection(Filter filter) {
+ if (filter.equals(Filter.INCLUDE)) {
+ return this;
+ }
+ if (filter.equals(Filter.EXCLUDE)) {
+ // TODO implement EmptyFeatureCollection( schema )
+ }
+ return new SubFeatureCollection(this, filter);
+ }
- public boolean isEmpty() {
- Iterator iterator = iterator();
- try {
- return !iterator.hasNext();
- }
- finally {
- if( iterator instanceof FeatureIterator){
- ((FeatureIterator<?>)iterator).close();
- }
- }
- }
+ public boolean isEmpty() {
+ SimpleFeatureIterator iterator = features();
+ try {
+ return !iterator.hasNext();
+ } finally {
+ iterator.close();
+ }
+ }
public void accepts(org.opengis.feature.FeatureVisitor visitor, org.opengis.util.ProgressListener progress) {
- Iterator iterator = null;
- // if( progress == null ) progress = new NullProgressListener();
+ if( progress == null ) {
+ progress = new NullProgressListener();
+ }
+ SimpleFeatureIterator iterator = features();
+
try{
float size = size();
float position = 0;
progress.started();
- for( iterator = iterator(); !progress.isCanceled() && iterator.hasNext(); progress.progress( position++/size )){
+ while( !progress.isCanceled() && iterator.hasNext()){
try {
SimpleFeature feature = (SimpleFeature) iterator.next();
visitor.visit(feature);
@@ -187,13 +166,12 @@ public void accepts(org.opengis.feature.FeatureVisitor visitor, org.opengis.util
catch( Exception erp ){
progress.exceptionOccurred( erp );
}
+ progress.progress( position++/size );
}
}
finally {
progress.complete();
- if( iterator instanceof FeatureIterator){
- ((FeatureIterator<?>)iterator).close();
- }
+ iterator.close();
}
}
View
7 modules/library/main/src/main/java/org/geotools/feature/collection/SubFeatureList.java
@@ -28,6 +28,7 @@
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.factory.CommonFactoryFinder;
+import org.geotools.feature.FeatureCollection;
import org.geotools.util.SoftValueHashMap;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.filter.Filter;
@@ -39,7 +40,11 @@
import org.opengis.filter.sort.SortOrder;
/**
- *
+ * Default implementation of {@link FeatureCollection#sort(SortBy)}.
+ * <p>
+ * This implementation is not suitable for working with large content as it makes
+ * use of memory both when eastablishing an initial sort order, and subsequently
+ * to hold a list of FeatureId.
*
* @source $URL$
*/
View
51 modules/library/main/src/test/java/org/geotools/data/memory/MemoryFeatureCollectionTest.java
@@ -16,12 +16,16 @@
*/
package org.geotools.data.memory;
+import java.io.Closeable;
import java.util.Arrays;
+import java.util.Iterator;
import org.geotools.data.DataTestCase;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
+import org.geotools.feature.collection.FilteredIterator;
import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.opengis.feature.simple.SimpleFeature;
/**
*
@@ -84,8 +88,7 @@ public void testResources(){
catch( IllegalStateException closed ){
}
}
-
-
+
public void testBounds() {
MemoryFeatureCollection rivers = new MemoryFeatureCollection(riverType);
ReferencedEnvelope expected = new ReferencedEnvelope();
@@ -100,10 +103,52 @@ public void testBounds() {
assertEquals( expected, rivers.getBounds() );
}
+ /**
+ * This feature collection is still implementing Collection so we best check it works
+ */
+ public void testIterator() throws Exception {
+ int count=0;
+ Iterator<SimpleFeature> it = roads.iterator();
+ try {
+ while( it.hasNext() ){
+ SimpleFeature feature = it.next();
+ count++;
+ }
+ } finally {
+ if( it instanceof Closeable){
+ ((Closeable)it).close();
+ }
+ }
+ assertEquals( roads.size(), count );
+
+ count=0;
+ FilteredIterator<SimpleFeature> filteredIterator = new FilteredIterator<SimpleFeature>( roads, rd12Filter );
+ try {
+ while( filteredIterator.hasNext() ){
+ SimpleFeature feature = filteredIterator.next();
+ count++;
+ }
+ } finally {
+ filteredIterator.close();
+ }
+ assertEquals( rd12Filter.getIDs().size(), count );
+ }
public void testSubCollection(){
+ int count = 0;
+ SimpleFeatureIterator it = roads.features();
+ try {
+ while( it.hasNext() ){
+ SimpleFeature feature = it.next();
+ if( rd12Filter.evaluate( feature )){
+ count++;
+ }
+ }
+ } finally {
+ it.close();
+ }
SimpleFeatureCollection sub = roads.subCollection( rd12Filter );
- assertEquals( 2, sub.size() );
+ assertEquals( count, sub.size() );
}
public void testSubSubCollection(){
SimpleFeatureCollection sub = roads.subCollection( rd12Filter );
Please sign in to comment.
Something went wrong with that request. Please try again.