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.data.collection;
017:
018: import java.io.IOException;
019: import java.util.Iterator;
020:
021: import org.geotools.data.AbstractDataStore;
022: import org.geotools.data.DataSourceException;
023: import org.geotools.data.FeatureReader;
024: import org.geotools.data.Query;
025: import org.geotools.data.SchemaNotFoundException;
026: import org.geotools.data.Transaction;
027: import org.geotools.feature.CollectionEvent;
028: import org.geotools.feature.CollectionListener;
029: import org.geotools.feature.DefaultFeatureType;
030: import org.geotools.feature.Feature;
031: import org.geotools.feature.FeatureCollection;
032: import org.geotools.feature.FeatureIterator;
033: import org.geotools.feature.FeatureType;
034: import org.opengis.filter.Filter;
035:
036: import com.vividsolutions.jts.geom.Envelope;
037:
038: /**
039: * Simple data store wrapper for feature collections. Allows to use feature collections in the user
040: * interface layer and everything else where a data store or a feature source is needed.
041: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/data/collection/CollectionDataStore.java $
042: */
043: public class CollectionDataStore extends AbstractDataStore {
044: FeatureType featureType;
045: FeatureCollection collection;
046:
047: /**
048: * Builds a data store wrapper on top of a feature collection
049: *
050: * @param collection
051: */
052: public CollectionDataStore(FeatureCollection collection) {
053: this .collection = collection;
054:
055: if (collection.size() == 0) {
056: this .featureType = DefaultFeatureType.EMPTY;
057: } else {
058: Iterator iter = null;
059: try {
060: iter = collection.iterator();
061: this .featureType = ((Feature) iter.next())
062: .getFeatureType();
063: } finally {
064: if (iter != null)
065: collection.close(iter);
066: }
067: }
068:
069: collection.addListener(new FeatureCollectionListener());
070: }
071:
072: /**
073: * @see org.geotools.data.DataStore#getTypeNames()
074: */
075: public String[] getTypeNames() {
076: return new String[] { featureType.getTypeName() };
077: }
078:
079: /**
080: * @see org.geotools.data.DataStore#getSchema(java.lang.String)
081: */
082: public FeatureType getSchema(String typeName) throws IOException {
083: if ((typeName != null)
084: && typeName.equals(featureType.getTypeName())) {
085: return featureType;
086: }
087:
088: throw new IOException(typeName + " not available");
089: }
090:
091: /**
092: * Provides FeatureReader over the entire contents of <code>typeName</code>.
093: *
094: * <p>
095: * Implements getFeatureReader contract for AbstractDataStore.
096: * </p>
097: *
098: * @param typeName
099: *
100: *
101: * @throws IOException If typeName could not be found
102: * @throws DataSourceException See IOException
103: *
104: * @see org.geotools.data.AbstractDataStore#getFeatureSource(java.lang.String)
105: */
106: public FeatureReader getFeatureReader(final String typeName)
107: throws IOException {
108: return new DelegateFeatureReader(getSchema(typeName),
109: collection.features());
110: }
111:
112: /**
113: * Returns the feature collection held by this data store
114: *
115: */
116: public FeatureCollection getCollection() {
117: return collection;
118: }
119:
120: /**
121: * @throws SchemaNotFoundException
122: * @see org.geotools.data.AbstractDataStore#getBounds(java.lang.String,
123: * org.geotools.data.Query)
124: */
125: protected Envelope getBounds(Query query)
126: throws SchemaNotFoundException {
127: String featureTypeName = query.getTypeName();
128: if (!featureType.getTypeName().equals(featureTypeName)) {
129: throw new SchemaNotFoundException(featureTypeName);
130: }
131:
132: return getBoundsInternal(query);
133: }
134:
135: /**
136: * @param query
137: */
138: protected Envelope getBoundsInternal(Query query) {
139: FeatureIterator iterator = collection.features();
140: Envelope envelope = null;
141:
142: if (iterator.hasNext()) {
143: int count = 1;
144: Filter filter = query.getFilter();
145: envelope = iterator.next().getDefaultGeometry()
146: .getEnvelopeInternal();
147:
148: while (iterator.hasNext()
149: && (count < query.getMaxFeatures())) {
150: Feature feature = iterator.next();
151:
152: if (filter.evaluate(feature)) {
153: count++;
154: envelope
155: .expandToInclude(feature
156: .getDefaultGeometry()
157: .getEnvelopeInternal());
158: }
159: }
160: }
161:
162: return envelope;
163:
164: }
165:
166: /**
167: * @see org.geotools.data.AbstractDataStore#getCount(java.lang.String, org.geotools.data.Query)
168: */
169: protected int getCount(Query query) throws IOException {
170: String featureTypeName = query.getTypeName();
171: if (!featureType.getTypeName().equals(featureTypeName)) {
172: throw new SchemaNotFoundException(featureTypeName);
173: }
174: int count = 0;
175: FeatureIterator iterator = collection.features();
176:
177: Filter filter = query.getFilter();
178:
179: while (iterator.hasNext() && (count < query.getMaxFeatures())) {
180: if (filter.evaluate(iterator.next())) {
181: count++;
182: }
183: }
184:
185: return count;
186: }
187:
188: /**
189: * Simple listener that forwards collection events into data store events
190: *
191: * @author aaime
192: */
193: private class FeatureCollectionListener implements
194: CollectionListener {
195: public void collectionChanged(CollectionEvent tce) {
196: String typeName = featureType.getTypeName();
197: Envelope bounds = null;
198:
199: bounds = getBoundsInternal(Query.ALL);
200:
201: switch (tce.getEventType()) {
202: case CollectionEvent.FEATURES_ADDED:
203: listenerManager.fireFeaturesAdded(typeName,
204: Transaction.AUTO_COMMIT, bounds, false);
205:
206: break;
207:
208: case CollectionEvent.FEATURES_CHANGED:
209: listenerManager.fireFeaturesChanged(typeName,
210: Transaction.AUTO_COMMIT, bounds, false);
211:
212: break;
213:
214: case CollectionEvent.FEATURES_REMOVED:
215: listenerManager.fireFeaturesRemoved(typeName,
216: Transaction.AUTO_COMMIT, bounds, false);
217:
218: break;
219: }
220: }
221: }
222: }
|