001: package org.geotools.data.gml;
002:
003: import java.io.BufferedInputStream;
004: import java.io.File;
005: import java.io.FileInputStream;
006: import java.io.IOException;
007: import java.io.InputStream;
008: import java.net.URI;
009: import java.net.URISyntaxException;
010: import java.util.ArrayList;
011: import java.util.Iterator;
012: import java.util.List;
013:
014: import org.eclipse.xsd.XSDElementDeclaration;
015: import org.eclipse.xsd.XSDSchema;
016: import org.eclipse.xsd.XSDTypeDefinition;
017: import org.eclipse.xsd.util.XSDSchemaLocationResolver;
018: import org.geotools.data.DataSourceException;
019: import org.geotools.data.store.AbstractDataStore2;
020: import org.geotools.feature.FeatureType;
021: import org.geotools.gml3.ApplicationSchemaConfiguration;
022: import org.geotools.gml3.GMLConfiguration;
023: import org.geotools.gml3.bindings.GML;
024: import org.geotools.gml3.bindings.GML3ParsingUtils;
025: import org.geotools.xml.BindingWalkerFactory;
026: import org.geotools.xml.Configuration;
027: import org.geotools.xml.Schemas;
028: import org.geotools.xml.impl.BindingLoader;
029: import org.geotools.xml.impl.BindingWalkerFactoryImpl;
030: import org.geotools.xml.impl.TypeWalker;
031: import org.picocontainer.MutablePicoContainer;
032: import org.picocontainer.defaults.DefaultPicoContainer;
033: import org.xmlpull.v1.XmlPullParser;
034: import org.xmlpull.v1.XmlPullParserException;
035: import org.xmlpull.v1.XmlPullParserFactory;
036:
037: public class GMLDataStore extends AbstractDataStore2 {
038:
039: /**
040: * Document location
041: */
042: String location;
043: /**
044: * Application schema / parser configuration
045: */
046: Configuration configuration;
047:
048: /**
049: * Creates a new datastore from an instance document.
050: * <p>
051: * Using this constructor forces the datastore to infer the application schema directly
052: * from the instance document.
053: * </p>
054: *
055: * @param location The location ( as a uri ) of the instance document.
056: */
057: public GMLDataStore(String location) {
058: this (location, null);
059: }
060:
061: /**
062: * Creates a new datastore from an instance document and application schema configuration.
063: *
064: * @param location The location ( as a uri ) of the instance document.
065: * @param configuration The application schema configuration.
066: */
067: public GMLDataStore(String location, Configuration configuration) {
068: this .location = location;
069: this .configuration = configuration;
070: }
071:
072: /**
073: * @return The location of the instance document to parse.
074: */
075: String getLocation() {
076: return location;
077: }
078:
079: /**
080: * @return the application schema configuration
081: */
082: Configuration getConfiguration() {
083: return configuration;
084: }
085:
086: /**
087: * Configuration accessor, which ensures a configuration is returned by infering it from
088: * the instance document if need be, or throwing an exception otherwise.
089: *
090: * @return
091: * @throws DataSourceException
092: */
093: Configuration configuration() throws DataSourceException {
094: if (configuration == null) {
095: synchronized (this ) {
096: if (configuration == null) {
097: try {
098: //parse some of the instance document to find out the schema location
099: InputStream input = document();
100:
101: //create stream parser
102: XmlPullParser parser = null;
103:
104: XmlPullParserFactory factory = XmlPullParserFactory
105: .newInstance();
106: factory.setNamespaceAware(true);
107: factory.setValidating(false);
108:
109: //parse root element
110: parser = factory.newPullParser();
111: parser.setInput(input, "UTF-8");
112: parser.nextTag();
113:
114: //look for schema location
115: for (int i = 0; i < parser.getAttributeCount(); i++) {
116: if ("schemaLocation".equals(parser
117: .getAttributeName(i))) {
118: String xsiSchemaLocation = parser
119: .getAttributeValue(i);
120: String[] split = xsiSchemaLocation
121: .split(" ");
122: if (split.length > 2) {
123: String msg = "Multiple schemaLocations not supported";
124: throw new DataSourceException(msg);
125: }
126:
127: String namespace = split[0];
128: String schemaLocation = split[1];
129:
130: configuration = new ApplicationSchemaConfiguration(
131: namespace, schemaLocation);
132:
133: break;
134: }
135: }
136:
137: //reset input stream
138: parser.setInput(null);
139: input.close();
140: } catch (Exception e) {
141: String msg = "Unable to determine schema from instance document";
142: throw new DataSourceException(msg, e);
143: }
144: }
145: }
146: }
147:
148: return configuration;
149: }
150:
151: /**
152: * @return The location of the application schema.
153: *
154: */
155: String schemaLocation() throws DataSourceException {
156: return configuration().getSchemaFileURL();
157: }
158:
159: protected List createContents() {
160: //TODO: this method should create content lazily.
161: try {
162: List contents = new ArrayList();
163: Configuration configuration = configuration();
164: XSDSchema schema = configuration.schema();
165:
166: //look for elements in the schema which are of type AbstractFeatureType
167: for (Iterator e = schema.getElementDeclarations()
168: .iterator(); e.hasNext();) {
169: XSDElementDeclaration element = (XSDElementDeclaration) e
170: .next();
171: if (!configuration.getNamespaceURI().equals(
172: element.getTargetNamespace()))
173: continue;
174:
175: final ArrayList isFeatureType = new ArrayList();
176: TypeWalker.Visitor visitor = new TypeWalker.Visitor() {
177:
178: public boolean visit(XSDTypeDefinition type) {
179: if (GML.NAMESPACE.equals(type
180: .getTargetNamespace())
181: && GML.AbstractFeatureCollectionType
182: .getLocalPart().equals(
183: type.getName())) {
184: return false;
185: }
186:
187: if (GML.NAMESPACE.equals(type
188: .getTargetNamespace())
189: && GML.AbstractFeatureType
190: .getLocalPart().equals(
191: type.getName())) {
192: isFeatureType.add(Boolean.TRUE);
193: return false;
194: }
195:
196: return true;
197: }
198:
199: };
200:
201: XSDTypeDefinition type = element.getType()
202: .getBaseType();
203: new TypeWalker().walk(type, visitor);
204:
205: if (!isFeatureType.isEmpty()) {
206: FeatureType featureType = featureType(element);
207: contents.add(new GMLTypeEntry(this , featureType,
208: null));
209: }
210: }
211:
212: return contents;
213: } catch (IOException e) {
214: throw new RuntimeException(e);
215: }
216: }
217:
218: /**
219: * Helper method for transforming an xml feautre type to a geotools feature type.
220: * @param element
221: * @return
222: * @throws IOException
223: */
224: private FeatureType featureType(XSDElementDeclaration element)
225: throws IOException {
226:
227: //load up the bindings for type conversion
228: GMLConfiguration configuration = new GMLConfiguration();
229:
230: BindingLoader bindingLoader = new BindingLoader();
231: bindingLoader.setContainer(configuration
232: .setupBindings(bindingLoader.getContainer()));
233:
234: MutablePicoContainer context = new DefaultPicoContainer();
235: context = configuration.setupContext(context);
236:
237: BindingWalkerFactory bwFactory = new BindingWalkerFactoryImpl(
238: bindingLoader, context);
239: try {
240: return GML3ParsingUtils.featureType(element, bwFactory);
241: } catch (Exception e) {
242: throw (IOException) new IOException().initCause(e);
243: }
244: }
245:
246: /**
247: * @return An input stream for hte document.
248: */
249: InputStream document() throws IOException {
250: File location;
251: try {
252: location = new File(new URI(getLocation()));
253: } catch (URISyntaxException e) {
254: throw (IOException) new IOException().initCause(e);
255: }
256: return new BufferedInputStream(new FileInputStream(location));
257: }
258:
259: /**
260: * Helper method which lazily parses the application schema.
261: *
262: * @throws IOException
263: */
264: XSDSchema schema() throws IOException {
265: return configuration().schema();
266: }
267: //
268: // if ( schema == null ) {
269: // synchronized ( this ) {
270: // if ( schema == null ) {
271: // GMLConfiguration configuration = new GMLConfiguration();
272: //
273: // //get all the necessary schema locations
274: // List dependencies = configuration.allDependencies();
275: // List resolvers = new ArrayList();
276: // for ( Iterator d = dependencies.iterator(); d.hasNext(); ) {
277: // Configuration dependency = (Configuration) d.next();
278: // XSDSchemaLocationResolver resolver = dependency.getSchemaLocationResolver();
279: // if ( resolver != null ) {
280: // resolvers.add( resolver );
281: // }
282: // }
283: //
284: // //if a schema location was specified, add one for it
285: // if ( schemaLocation == null ) {
286: // //parse some of the instance document to find out the schema location
287: // InputStream input = document();
288: //
289: // //create stream parser
290: // XmlPullParser parser = null;
291: //
292: // try {
293: // XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
294: // factory.setNamespaceAware(true);
295: // factory.setValidating(false);
296: //
297: // //parse root element
298: // parser = factory.newPullParser();
299: // parser.setInput( input, "UTF-8" );
300: // parser.nextTag();
301: //
302: // //look for schema location
303: // for ( int i = 0; i < parser.getAttributeCount(); i++ ) {
304: // if ( "schemaLocation".equals( parser.getAttributeName( i ) ) ) {
305: // String xsiSchemaLocation = parser.getAttributeValue( i );
306: // String[] split = xsiSchemaLocation.split( " " );
307: // for ( int j = 0; j < split.length; j += 2 ) {
308: // if ( namespace.equals( split[ j ] ) ) {
309: // schemaLocation = split[ j + 1 ];
310: // break;
311: // }
312: // }
313: //
314: // break;
315: // }
316: // }
317: //
318: // //reset input stream
319: // parser.setInput( null );
320: // input.close();
321: // }
322: // catch (XmlPullParserException e) {
323: // throw (IOException) new IOException().initCause( e );
324: // }
325: // }
326: //
327: // if ( schemaLocation == null ) {
328: // throw new DataSourceException( "Unable to determine application schema location ");
329: // }
330: //
331: // schema = Schemas.parse( schemaLocation, null, resolvers );
332: // }
333: // }
334: // }
335: //
336: // return schema;
337: // }
338: }
|