001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.feature.collection;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.Collections;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.NoSuchElementException;
025: import java.util.Set;
026:
027: import org.geotools.data.collection.ResourceCollection;
028: import org.geotools.feature.CollectionListener;
029: import org.geotools.feature.DefaultFeatureCollection;
030: import org.geotools.feature.Feature;
031: import org.geotools.feature.FeatureCollection;
032: import org.geotools.feature.FeatureType;
033: import org.geotools.feature.IllegalAttributeException;
034:
035: import com.vividsolutions.jts.geom.Envelope;
036: import com.vividsolutions.jts.geom.Geometry;
037:
038: /**
039: * This is *not* a Feature - it is a Delegate used by FeatureCollection
040: * implementations as "mix-in", provides implementation of featureCollection
041: * events, featureType, and attribute access.
042: * <p>
043: * To use cut&paste the following code exactly:<pre>
044: * <code>
045: *
046: * </code>
047: * </p>
048: * <p>
049: * On the bright side this means we can "fix" all the FeatureCollection implementations
050: * in one fell-swoop.
051: * </p>
052: *
053: * @author Jody Garnett, Refractions Reserach, Inc.
054: * @since GeoTools 2.2
055: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/feature/collection/FeatureState.java $
056: */
057: public abstract class FeatureState {
058:
059: protected Envelope bounds = null;
060: protected ResourceCollection data;
061:
062: protected FeatureState(ResourceCollection collection) {
063: data = collection;
064: }
065:
066: //
067: // FeatureCollection Event Support
068: //
069:
070: /**
071: * Adds a listener for collection events.
072: *
073: * @param listener The listener to add
074: */
075: abstract public void addListener(CollectionListener listener);
076:
077: /**
078: * Removes a listener for collection events.
079: *
080: * @param listener The listener to remove
081: */
082: abstract public void removeListener(CollectionListener listener);
083:
084: /**
085: * To let listeners know that something has changed.
086: */
087: abstract protected void fireChange(Feature[] features, int type);
088:
089: protected void fireChange(Feature feature, int type) {
090: fireChange(new Feature[] { feature }, type);
091: }
092:
093: protected void fireChange(Collection coll, int type) {
094: Feature[] features = new Feature[coll.size()];
095: features = (Feature[]) coll.toArray(features);
096: fireChange(features, type);
097: }
098:
099: //
100: // Feature Methods
101: //
102: /**
103: * Gets the bounding box for the features in this feature collection.
104: *
105: * @return the envelope of the geometries contained by this feature
106: * collection.
107: */
108: public Envelope getBounds() {
109: if (bounds == null) {
110: bounds = new Envelope();
111: Iterator i = data.iterator();
112: try {
113: while (i.hasNext()) {
114: Envelope geomBounds = ((Feature) i.next())
115: .getBounds();
116: if (!geomBounds.isNull()) {
117: bounds.expandToInclude(geomBounds);
118: }
119: }
120: } finally {
121: data.close(i);
122: }
123: }
124: return bounds;
125: }
126:
127: public abstract FeatureType getFeatureType();
128:
129: public abstract FeatureType getChildFeatureType();
130:
131: public abstract String getId();
132:
133: public FeatureCollection getParent() {
134: return null;
135: }
136:
137: public void setParent(FeatureCollection parent) {
138: throw new UnsupportedOperationException();
139: }
140:
141: public Object[] getAttributes(Object[] attributes) {
142: List list = (List) getAttribute(0);
143: return list.toArray(attributes);
144: }
145:
146: /**
147: * Not really interested yet ..
148: */
149: public Object getAttribute(String xPath) {
150: if (xPath.indexOf(getFeatureType().getTypeName()) > -1)
151: if (xPath.endsWith("]")) {
152: return getAttribute(0);
153: } else {
154: return getAttribute(0);
155: }
156: return null;
157: }
158:
159: public Object getAttribute(int index) {
160: if (index == 0) {
161: Iterator i = data.iterator();
162: List list = new ArrayList();
163: try {
164: while (i.hasNext()) {
165: Feature feature = (Feature) i.next();
166: list.add(feature);
167: }
168: return list;
169: } catch (NoSuchElementException e) {
170: return Collections.EMPTY_LIST; // could not find contents
171: } finally {
172: data.close(i);
173: }
174: }
175: return null;
176: }
177:
178: public void setAttribute(int position, Object val)
179: throws IllegalAttributeException,
180: ArrayIndexOutOfBoundsException {
181: if (position == 0 && val instanceof Collection) {
182: Collection newStuff = (Collection) val;
183: if (!isFeatures(newStuff)) {
184: throw new IllegalAttributeException(
185: "Content must be features");
186: }
187: data.clear(); // clean out previous contents!
188: Iterator i = newStuff.iterator();
189: try {
190: while (i.hasNext()) {
191: Feature feature = (Feature) i.next();
192: data.add(feature);
193: }
194: } finally {
195: data.close(i);
196: }
197: //fireChange(nw,0);
198: }
199: }
200:
201: public int getNumberOfAttributes() {
202: return getFeatureType().getAttributeCount();
203: }
204:
205: public void setAttribute(String xPath, Object attribute)
206: throws IllegalAttributeException {
207: if (xPath.indexOf(getFeatureType().getTypeName()) > -1) {
208: if (xPath.endsWith("]")) {
209: // TODO get index and grab it
210: } else {
211: setAttribute(0, attribute);
212: }
213: }
214: }
215:
216: public Geometry getDefaultGeometry() {
217: return null;
218: }
219:
220: public void setDefaultGeometry(Geometry geometry)
221: throws IllegalAttributeException {
222: throw new IllegalAttributeException(
223: "DefaultGeometry not supported");
224: }
225:
226: //
227: // Utility Methods
228: //
229: /**
230: * Get the set of fids for the provided collection.
231: * <p>
232: * By doing a quick pass through the collection we can do
233: * comparisons based on Feature ID (rather then collection
234: * membership).
235: * </p>
236: * <p>
237: * A subclass that tracks its FID information may wish to override
238: * this method.
239: * </p>
240: */
241: public static Set fids(Collection stuff) {
242: if (stuff instanceof DefaultFeatureCollection) {
243: DefaultFeatureCollection features = (DefaultFeatureCollection) stuff;
244: return features.fids();
245: }
246:
247: Iterator iterator = stuff.iterator();
248: Set fids = new HashSet();
249: try {
250: while (iterator.hasNext()) {
251: Feature feature = (Feature) iterator.next();
252: fids.add(feature.getID());
253: }
254: } finally {
255: if (stuff instanceof ResourceCollection) {
256: ((ResourceCollection) stuff).close(iterator);
257: }
258: }
259: return fids;
260: }
261:
262: /** Test if collection is all features! */
263: public static boolean isFeatures(Collection stuff) {
264: if (stuff instanceof FeatureCollection)
265: return true;
266:
267: Iterator i = stuff.iterator();
268: try {
269: while (i.hasNext()) {
270: if (!(i.next() instanceof Feature))
271: return false;
272: }
273: } finally {
274: if (stuff instanceof ResourceCollection) {
275: ((ResourceCollection) stuff).close(i);
276: }
277: }
278: return true;
279: }
280:
281: }
|