001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 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.catalog;
017:
018: import java.io.IOException;
019: import java.net.URI;
020: import java.net.URISyntaxException;
021: import java.util.logging.Level;
022:
023: import org.geotools.catalog.defaults.DefaultGeoResourceInfo;
024: import org.geotools.data.DataStore;
025: import org.geotools.data.FeatureSource;
026: import org.geotools.feature.FeatureIterator;
027: import org.geotools.feature.FeatureType;
028: import org.geotools.geometry.jts.ReferencedEnvelope;
029: import org.geotools.util.ProgressListener;
030: import org.opengis.referencing.crs.CoordinateReferenceSystem;
031:
032: import com.vividsolutions.jts.geom.Envelope;
033:
034: /**
035: * Resource implementation for resources which can map or resolve to a
036: * {@link org.geotools.data.FeatureSource}.
037: * <p>
038: * Subclasses may with to override the methods:
039: * <ul>
040: * <li>{@link #createMetaData(FeatureSource, ProgressListener)}
041: * </ul>
042: *
043: * In addition, subclasses may wish to <b>extend</b> the following methods in
044: * order to support additional resolves.
045: * <ul>
046: * <li>{@link #canResolve(Class)}
047: * <li>{@link #resolve(Class, ProgressListener)}
048: * </ul>
049: *
050: * </p>
051: *
052: * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
053: *
054: */
055: public class FeatureSourceGeoResource extends AbstractGeoResource {
056:
057: /**
058: * Parent handle
059: */
060: DataStoreService parent;
061: /**
062: * Feature type name
063: */
064: String name;
065: /**
066: * Cached feature source
067: */
068: FeatureSource source;
069: /**
070: * metadata object
071: */
072: GeoResourceInfo info;
073:
074: public FeatureSourceGeoResource(DataStoreService parent, String name) {
075: this .parent = parent;
076: this .name = name;
077: }
078:
079: /**
080: * @return The name of the feature source, feature type.
081: */
082: public String getName() {
083: return name;
084: }
085:
086: /**
087: * Supports the required GeoResource resolves with an additional resolves
088: * to:
089: * <ul>
090: * <li>{@link FeatureSourceGeoResource}
091: * <li>{@link FeatureType}
092: * <li>{@link DataStore}
093: * </ul>
094: * <p>
095: * Subclasses may wish to extend this method.
096: * </p>
097: */
098: public boolean canResolve(Class adaptee) {
099: if (adaptee == null)
100: return false;
101:
102: return adaptee.isAssignableFrom(Service.class)
103: || adaptee.isAssignableFrom(GeoResourceInfo.class)
104: || adaptee.isAssignableFrom(FeatureSource.class)
105: || adaptee.isAssignableFrom(FeatureType.class)
106: || adaptee.isAssignableFrom(DataStore.class);
107: }
108:
109: /**
110: * Supports the required GeoResource resolves with an additional resolves
111: * to:
112: * <ul>
113: * <li>{@link FeatureSourceGeoResource}
114: * <li>{@link FeatureType}
115: * <li>{@link DataStore}
116: * </ul>
117: * <p>
118: * Subclasses may wish to extend this method.
119: * </p>
120: */
121: public Object resolve(Class adaptee, ProgressListener monitor)
122: throws IOException {
123:
124: if (adaptee == null)
125: return null;
126:
127: if (adaptee.isAssignableFrom(Service.class))
128: return parent;
129:
130: if (adaptee.isAssignableFrom(GeoResourceInfo.class))
131: return getInfo(monitor);
132:
133: if (adaptee.isAssignableFrom(FeatureSource.class))
134: return featureSource(monitor);
135:
136: if (adaptee.isAssignableFrom(FeatureType.class))
137: return parent.dataStore(monitor).getSchema(name);
138:
139: if (adaptee.isAssignableFrom(DataStore.class))
140: return parent.dataStore(monitor);
141:
142: return null;
143: }
144:
145: /**
146: * Returns the status of the handle based on the following.
147: *
148: * 1. If a non-null error has been set with {@link #setMessage(Throwable)}
149: * then the handle is {@link Status#BROKEN}.
150: * 2. If {@link #source} is non-null the handle is {@link Status#CONNECTED}.
151: * 3. The handle is {@link Status#NOTCONNECTED}.
152: */
153: public Status getStatus() {
154: if (getMessage() != null)
155: return Status.BROKEN;
156:
157: if (source != null)
158: return Status.CONNECTED;
159:
160: return Status.NOTCONNECTED;
161: }
162:
163: public GeoResourceInfo getInfo(ProgressListener monitor)
164: throws IOException {
165: if (info == null) {
166:
167: DataStore dataStore = parent.dataStore(monitor);
168:
169: synchronized (dataStore) {
170: if (info == null) {
171: try {
172: info = createMetaData(featureSource(monitor),
173: monitor);
174: setMessage(null);
175: } catch (Throwable t) {
176: String msg = "unable to create metadata";
177: logger.log(Level.SEVERE, msg, t);
178: setMessage(t);
179: }
180: }
181: }
182: }
183:
184: return info;
185: }
186:
187: /**
188: * Creates the resource metadata.
189: * <p>
190: * Data providers providing custom metadata need to override this method.
191: * The default implementation provided the following metadata mappings:
192: *
193: * <ul>
194: * <li>{@link FeatureSource#getBounds()} -> {@link GeoResourceInfo#getBounds()}
195: * <li>{@link FeatureType#getTypeName()} -> {@link GeoResourceInfo#getName()}
196: * <li>{@link FeatureType#getNamespace()()} -> {@link GeoResourceInfo#getSchema()()}
197: * </ul>
198: * </p>
199: *
200: * @param source the underlying FeatureSource
201: * @param monitor a ProgressListener for blocking calls.
202: *
203: * @return The resource info.
204: */
205: protected GeoResourceInfo createMetaData(FeatureSource source,
206: ProgressListener monitor) throws IOException {
207:
208: //calculate bounds
209: ReferencedEnvelope rBounds = null;
210: Envelope bounds = source.getBounds();
211: if (bounds != null) {
212: //we have an "optmized bounds", do we have a crs?
213: if (bounds instanceof ReferencedEnvelope) {
214: rBounds = (ReferencedEnvelope) bounds;
215: }
216:
217: if (rBounds == null) {
218: //since we had an optimized bounds from feature source, we would
219: // like to avoid accessing the data, so check the type for
220: // crs info
221: FeatureType schema = source.getSchema();
222: if (schema.getDefaultGeometry() != null) {
223: CoordinateReferenceSystem crs = schema
224: .getDefaultGeometry().getCoordinateSystem();
225:
226: if (crs != null) {
227: rBounds = new ReferencedEnvelope(bounds, crs);
228: } else {
229: rBounds = null;
230: }
231: }
232: }
233:
234: if (rBounds == null) {
235: rBounds = new ReferencedEnvelope(bounds, null);
236: }
237: } else {
238: //manually calculate the bounds
239: bounds = new Envelope();
240:
241: FeatureIterator itr = source.getFeatures().features();
242: if (itr.hasNext()) {
243: bounds.init(itr.next().getBounds());
244: while (itr.hasNext()) {
245: bounds.expandToInclude(itr.next().getBounds());
246: }
247: }
248:
249: FeatureType schema = source.getSchema();
250: CoordinateReferenceSystem crs = null;
251: if (schema.getDefaultGeometry() != null) {
252: crs = schema.getDefaultGeometry().getCoordinateSystem();
253: }
254:
255: rBounds = new ReferencedEnvelope(bounds, crs);
256: }
257:
258: String name = source.getSchema().getTypeName();
259: URI schema = source.getSchema().getNamespace();
260:
261: return new DefaultGeoResourceInfo(null, name, null, schema,
262: rBounds, null, null);
263: }
264:
265: /**
266: * Uses the parent identifer, and tacks {@link #name} on as a fragment.
267: */
268: public URI getIdentifier() {
269: URI uri = parent.getIdentifier();
270:
271: try {
272: return new URI(uri.getScheme(), uri.getHost(), uri
273: .getPath(), name);
274: } catch (URISyntaxException e) {
275: String msg = "Unable to build uri identifer";
276: logger.log(Level.WARNING, msg, e);
277: setMessage(e);
278: }
279:
280: try {
281: return new URI(name);
282: } catch (URISyntaxException e) {
283: //shoult not happen
284: }
285:
286: return null;
287:
288: }
289:
290: protected FeatureSource featureSource(ProgressListener monitor) {
291:
292: if (source == null) {
293: DataStore dataStore = parent.dataStore(monitor);
294: try {
295: synchronized (dataStore) {
296: source = dataStore.getFeatureSource(name);
297: if (source == null)
298: throw new NullPointerException();
299:
300: setMessage(null);
301: return source;
302: }
303: } catch (Throwable t) {
304: String msg = "Unable to resolve feature source.";
305: logger.log(Level.SEVERE, msg, t);
306: setMessage(t);
307: }
308: }
309:
310: return source;
311: }
312:
313: protected FeatureType featureType(ProgressListener monitor) {
314: if (featureSource(monitor) != null)
315: return featureSource(monitor).getSchema();
316:
317: return null;
318: }
319: }
|