001: package org.geoserver.wfs;
002:
003: import java.util.Iterator;
004: import java.util.NoSuchElementException;
005:
006: import org.geotools.feature.Feature;
007: import org.geotools.feature.FeatureCollection;
008: import org.geotools.feature.FeatureIterator;
009: import org.geotools.feature.FeatureType;
010: import org.geotools.feature.GeometryAttributeType;
011: import org.geotools.feature.IllegalAttributeException;
012: import org.geotools.feature.collection.AbstractFeatureCollection;
013: import org.geotools.geometry.jts.ReferencedEnvelope;
014: import org.opengis.referencing.crs.CoordinateReferenceSystem;
015:
016: import com.vividsolutions.jts.geom.Envelope;
017: import com.vividsolutions.jts.geom.Geometry;
018:
019: /**
020: * A feature collection wrapping a base collection, returning features that do
021: * conform to the specified type (which has have a subset of the attributes in the
022: * original schema), and that do use the wrapped features to compute their bounds (so that
023: * the Feature bounds can be computed even if the visible attributes do not include geometries)
024: * @author Andrea Aime - TOPP
025: *
026: */
027: class FeatureBoundsFeatureCollection extends AbstractFeatureCollection {
028: FeatureCollection wrapped;
029:
030: /**
031: * Builds a new BoundsFeatureCollection
032: * @param wrapped the wrapped feature collection
033: * @param targetSchema the target schema
034: */
035: public FeatureBoundsFeatureCollection(FeatureCollection wrapped,
036: FeatureType targetSchema) {
037: super (targetSchema);
038: this .wrapped = wrapped;
039: }
040:
041: protected void closeIterator(Iterator close) {
042: ((BoundsIterator) close).close();
043: }
044:
045: protected Iterator openIterator() {
046: return new BoundsIterator(wrapped.features(), getSchema());
047: }
048:
049: public int size() {
050: return wrapped.size();
051: }
052:
053: /**
054: *
055: * @author Andrea Aime - TOPP
056: *
057: */
058: private static class BoundsIterator implements Iterator {
059: FeatureIterator wrapped;
060: FeatureType targetSchema;
061:
062: public BoundsIterator(FeatureIterator wrapped,
063: FeatureType targetSchema) {
064: this .wrapped = wrapped;
065: this .targetSchema = targetSchema;
066: }
067:
068: public void close() {
069: wrapped.close();
070: }
071:
072: public boolean hasNext() {
073: return wrapped.hasNext();
074: }
075:
076: public Object next() throws NoSuchElementException {
077: Feature base = wrapped.next();
078: return new BoundedFeature(base, targetSchema);
079: }
080:
081: public void remove() {
082: throw new UnsupportedOperationException(
083: "Removal is not supported");
084: }
085: }
086:
087: /**
088: * Wraps a Feature shaving off all attributes not included in the original type, but
089: * delegates bounds computation to the original feature.
090: * @author Andrea Aime - TOPP
091: *
092: */
093: private static class BoundedFeature implements Feature {
094: private Feature wrapped;
095:
096: private FeatureType type;
097:
098: public BoundedFeature(Feature wrapped, FeatureType type) {
099: this .wrapped = wrapped;
100: this .type = type;
101: }
102:
103: public Object getAttribute(int index) {
104: return wrapped.getAttribute(type.getAttributeType(index)
105: .getName());
106: }
107:
108: public Object getAttribute(String path) {
109: if (type.getAttributeType(path) == null)
110: return null;
111: return wrapped.getAttribute(path);
112: }
113:
114: public Object[] getAttributes(Object[] attributes) {
115: Object[] retval = attributes != null ? attributes
116: : new Object[type.getAttributeCount()];
117: for (int i = 0; i < retval.length; i++) {
118: retval[i] = wrapped.getAttribute(type.getAttributeType(
119: i).getName());
120: }
121: return retval;
122: }
123:
124: public ReferencedEnvelope getBounds() {
125: // we may not have the default geometry around in the reduced feature type,
126: // so let's output a referenced envelope if possible
127: if (wrapped.getFeatureType().getDefaultGeometry() != null) {
128: CoordinateReferenceSystem crs = wrapped
129: .getFeatureType().getDefaultGeometry()
130: .getCoordinateSystem();
131: if (crs != null) {
132: return new ReferencedEnvelope(wrapped.getBounds(),
133: crs);
134: }
135: }
136: return wrapped.getBounds();
137: }
138:
139: public Geometry getDefaultGeometry() {
140: return getPrimaryGeometry();
141: }
142:
143: public Geometry getPrimaryGeometry() {
144: GeometryAttributeType defaultGeometry = type
145: .getDefaultGeometry();
146: if (defaultGeometry == null)
147: return null;
148: return (Geometry) wrapped.getAttribute(defaultGeometry
149: .getName());
150: }
151:
152: public FeatureType getFeatureType() {
153: return type;
154: }
155:
156: public String getID() {
157: return wrapped.getID();
158: }
159:
160: public int getNumberOfAttributes() {
161: return type.getAttributeCount();
162: }
163:
164: public void setAttribute(int position, Object val)
165: throws IllegalAttributeException,
166: ArrayIndexOutOfBoundsException {
167: throw new UnsupportedOperationException(
168: "This feature wrapper is read only");
169: }
170:
171: public void setAttribute(String path, Object attribute)
172: throws IllegalAttributeException {
173: throw new UnsupportedOperationException(
174: "This feature wrapper is read only");
175: }
176:
177: public void setDefaultGeometry(Geometry geometry)
178: throws IllegalAttributeException {
179: setPrimaryGeometry(geometry);
180: }
181:
182: public void setPrimaryGeometry(Geometry geometry)
183: throws IllegalAttributeException {
184: throw new UnsupportedOperationException(
185: "This feature wrapper is read only");
186: }
187:
188: }
189: }
|