001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-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; either
009: * version 2.1 of the License, or (at your option) any later version.
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.vpf;
017:
018: import java.io.File;
019: import java.io.IOException;
020: import java.net.URI;
021: import java.util.AbstractList;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Vector;
025:
026: import org.geotools.data.vpf.file.VPFFile;
027: import org.geotools.data.vpf.file.VPFFileFactory;
028: import org.geotools.data.vpf.ifc.DataTypesDefinition;
029: import org.geotools.data.vpf.ifc.FileConstants;
030: import org.geotools.data.vpf.readers.AreaGeometryFactory;
031: import org.geotools.data.vpf.readers.ConnectedNodeGeometryFactory;
032: import org.geotools.data.vpf.readers.EntityNodeGeometryFactory;
033: import org.geotools.data.vpf.readers.LineGeometryFactory;
034: import org.geotools.data.vpf.readers.TextGeometryFactory;
035: import org.geotools.data.vpf.readers.VPFGeometryFactory;
036: import org.geotools.feature.AttributeType;
037: import org.geotools.feature.AttributeTypeFactory;
038: import org.geotools.feature.DefaultFeatureType;
039: import org.geotools.feature.Feature;
040: import org.geotools.feature.FeatureType;
041: import org.geotools.feature.GeometryAttributeType;
042: import org.geotools.feature.IllegalAttributeException;
043: import org.geotools.feature.SchemaException;
044: import org.geotools.feature.type.AnnotationFeatureType;
045: import org.opengis.referencing.crs.CoordinateReferenceSystem;
046:
047: import com.vividsolutions.jts.geom.Geometry;
048:
049: /**
050: * A VPF feature class. Note that feature classes may contain one
051: * or more feature types. However, all of the feature types of a
052: * feature class share the same schema. A feature type will therefore
053: * delegate its schema related operations to its feature class.
054: *
055: * @author <a href="mailto:jeff@ionicenterprise.com">Jeff Yutzler</a>
056: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/vpf/src/main/java/org/geotools/data/vpf/VPFFeatureClass.java $
057: */
058: public class VPFFeatureClass implements DataTypesDefinition,
059: FileConstants, FeatureType {
060: /**
061: * The contained feature type
062: */
063: private DefaultFeatureType featureType;
064:
065: /**
066: * The columns that are part of this feature class
067: */
068: private final List columns = new Vector();
069:
070: /** The coverage this feature class is part of */
071: private final VPFCoverage coverage;
072:
073: /** The path of the directory containing this feature class */
074: private final String directoryName;
075:
076: /** A list of files which are read to retrieve data for this feature class */
077: private final AbstractList fileList = new Vector();
078:
079: /** A list of ColumnPair objects which identify the file joins */
080: private final AbstractList joinList = new Vector();
081:
082: /** The name of the feature class */
083: private final String typeName;
084:
085: /** The uri of the namespace in which features should be created */
086: private final URI namespace;
087:
088: /**
089: * The geometry factory for this feature class
090: */
091: private VPFGeometryFactory geometryFactory;
092:
093: /**
094: * Indicator that the feature type is a text feature.
095: */
096: private boolean textTypeFeature = false;
097:
098: /**
099: * Constructor
100: *
101: * @param cCoverage the owning coverage
102: * @param cName the name of the class
103: * @param cDirectoryName the directory containing the class
104: * @throws SchemaException For problems making one of the feature classes as a FeatureType.
105: */
106: public VPFFeatureClass(VPFCoverage cCoverage, String cName,
107: String cDirectoryName) throws SchemaException {
108: this (cCoverage, cName, cDirectoryName, null);
109: }
110:
111: /**
112: * Constructor
113: *
114: * @param cCoverage the owning coverage
115: * @param cName the name of the class
116: * @param cDirectoryName the directory containing the class
117: * @param cNamespace the namespace to create features with. If null then
118: * a default from VPFLibrary.DEFAULTNAMESPACE is assigned.
119: * @throws SchemaException For problems making one of the feature classes as a FeatureType.
120: */
121: public VPFFeatureClass(VPFCoverage cCoverage, String cName,
122: String cDirectoryName, URI cNamespace)
123: throws SchemaException {
124: coverage = cCoverage;
125: directoryName = cDirectoryName;
126: typeName = cName;
127: if (cNamespace == null) {
128: namespace = VPFLibrary.DEFAULT_NAMESPACE;
129: } else {
130: namespace = cNamespace;
131: }
132:
133: String fcsFileName = directoryName + File.separator + TABLE_FCS;
134:
135: try {
136: VPFFile fcsFile = (VPFFile) VPFFileFactory.getInstance()
137: .getFile(fcsFileName);
138: Iterator iter = fcsFile.readAllRows().iterator();
139:
140: while (iter.hasNext()) {
141: Feature feature = (Feature) iter.next();
142: String featureClassName = feature.getAttribute(
143: "feature_class").toString().trim();
144:
145: if (typeName.equals(featureClassName)) {
146: addFCS(feature);
147: }
148: }
149:
150: // Deal with the geometry column
151: iter = columns.iterator();
152:
153: GeometryAttributeType gat = null;
154: AttributeType geometryColumn = null;
155:
156: while (iter.hasNext()) {
157: geometryColumn = (AttributeType) iter.next();
158:
159: if (Geometry.class.isAssignableFrom(geometryColumn
160: .getType())) {
161: if (geometryColumn instanceof GeometryAttributeType) {
162: gat = (GeometryAttributeType) geometryColumn;
163: } else if (geometryColumn instanceof VPFColumn) {
164: gat = ((VPFColumn) geometryColumn)
165: .getGeometryAttributeType();
166: }
167: break;
168: }
169: }
170:
171: Vector super Types = new Vector();
172: // if it's a text geometry feature type add annotation as a super type
173: if (textTypeFeature) {
174: super Types.add(AnnotationFeatureType.ANNOTATION);
175: }
176:
177: featureType = new DefaultFeatureType(cName, namespace,
178: columns, super Types, gat);
179: } catch (IOException exp) {
180: //We've already searched the FCS file once successfully
181: //So this should never happen
182: exp.printStackTrace();
183: }
184: }
185:
186: /**
187: * Add the information from a new FCS row.
188: *
189: * @param row The FCS table row
190: */
191: private void addFCS(Feature row) //throws IOException
192: {
193: String table1 = row.getAttribute("table1").toString();
194: String table1Key = row.getAttribute("table1_key").toString();
195: String table2 = row.getAttribute("table2").toString();
196: String table2Key = row.getAttribute("table2_key").toString();
197:
198: try {
199: VPFFile vpfFile1 = VPFFileFactory.getInstance()
200: .getFile(
201: directoryName.concat(File.separator)
202: .concat(table1));
203: addFileToTable(vpfFile1);
204:
205: VPFFile vpfFile2 = null;
206: AttributeType joinColumn1 = (VPFColumn) vpfFile1
207: .getAttributeType(table1Key);
208: AttributeType joinColumn2;
209:
210: try {
211: vpfFile2 = VPFFileFactory.getInstance().getFile(
212: directoryName.concat(File.separator).concat(
213: table2));
214: addFileToTable(vpfFile2);
215: joinColumn2 = (VPFColumn) vpfFile2
216: .getAttributeType(table2Key);
217: } catch (IOException exc) {
218: fileList.add(null);
219:
220: // We need to add a geometry column
221: joinColumn2 = buildGeometryColumn(table2);
222: }
223:
224: // FCS's that are the inverse of existing ones are not needed
225: // But we should never get this far
226: if (!joinList.contains(new ColumnPair(joinColumn2,
227: joinColumn1))) {
228: joinList.add(new ColumnPair(joinColumn1, joinColumn2));
229: }
230: } catch (IOException exc) {
231: // File was not present
232: // which means it is for a geometry table
233: // we can safely ignore it for now
234: // exc.printStackTrace();
235: }
236: }
237:
238: /**
239: * Create a geometry column (usually for feature classes that
240: * make use of tiles so simple joins can not be used)
241: * @param table The name of the table containing the geometric primitives
242: * @return An <code>AttributeType</code> for the geometry column which is actually a <code>GeometryAttributeType</code>
243: */
244: private AttributeType buildGeometryColumn(String table) {
245: AttributeType result = null;
246:
247: table = table.trim().toLowerCase();
248:
249: // Why would the fileList already contain a null?
250: // if(!fileList.contains(null)){
251: CoordinateReferenceSystem crs = getCoverage().getLibrary()
252: .getCoordinateReferenceSystem();
253: if (crs != null) {
254: result = AttributeTypeFactory.newAttributeType("GEOMETRY",
255: Geometry.class, true, -1, null, crs);
256: } else {
257: result = AttributeTypeFactory.newAttributeType("GEOMETRY",
258: Geometry.class, true);
259: }
260: columns.add(result);
261:
262: setGeometryFactory(table);
263:
264: // }
265: return result;
266: }
267:
268: /**
269: * Identifies the type of geometry factory to use based on the
270: * name of the table containing the geometry, then constructs the
271: * appropriate geometry factory object.
272: * @param table The name of the geometry table
273: */
274: private void setGeometryFactory(String table) {
275: if (table.equals(EDGE_PRIMITIVE)) {
276: geometryFactory = new LineGeometryFactory();
277: } else if (table.equals(FACE_PRIMITIVE)) {
278: geometryFactory = new AreaGeometryFactory();
279: } else if (table.equals(CONNECTED_NODE_PRIMITIVE)) {
280: geometryFactory = new ConnectedNodeGeometryFactory();
281: } else if (table.equals(ENTITY_NODE_PRIMITIVE)) {
282: geometryFactory = new EntityNodeGeometryFactory();
283: } else if (table.equals(TEXT_PRIMITIVE)) {
284: geometryFactory = new TextGeometryFactory();
285: textTypeFeature = true;
286: }
287:
288: // if an invalid string is returned, there will be no geometry
289: }
290:
291: /**
292: * Adds all of the columns from a VPF file into the table. Note:
293: * This does not handle columns with the same name particularly well.
294: * Perhaps the xpath mechanism can be used to help here.
295: * @param vpfFile the <code>VPFFile</code> object to use
296: */
297: private void addFileToTable(VPFFile vpfFile) {
298: // Class columnClass;
299: boolean addPrimaryKey = fileList.isEmpty();
300:
301: // Check to see if we have already grabbed this file
302: if (!fileList.contains(vpfFile)) {
303: fileList.add(vpfFile);
304:
305: // Pull the columns off of the file and add them to our schema
306: // Except for the first file, ignore the first column since it is a join column
307: for (int inx = addPrimaryKey ? 0 : 1; inx < vpfFile
308: .getAttributeCount(); inx++) {
309: columns.add(vpfFile.getAttributeType(inx));
310: }
311: }
312: }
313:
314: /**
315: * The coverage that owns this feature class
316: * @return a <code>VPFCoverage</code> object
317: */
318: public VPFCoverage getCoverage() {
319: return coverage;
320: }
321:
322: /**
323: * The path to the directory that contains this feature class
324: *
325: * @return a <code>String</code> value representing the path to the directory.
326: */
327: public String getDirectoryName() {
328: return directoryName;
329: }
330:
331: /**
332: * Returns a list of file objects
333: *
334: * @return a <code>List</code> containing <code>VPFFile</code> objects.
335: */
336: public List getFileList() {
337: return fileList;
338: }
339:
340: /**
341: * DOCUMENT ME!
342: *
343: * @return a<code>List</code> containing <code>ColumnPair</code> objects
344: * which identify the file joins.
345: */
346: public List getJoinList() {
347: return joinList;
348: }
349:
350: /* (non-Javadoc)
351: * @see org.geotools.feature.FeatureType#getNamespace()
352: */
353: public URI getNamespace() {
354: return featureType.getNamespace();
355: }
356:
357: // not needed
358: // /* (non-Javadoc)
359: // * @see org.geotools.feature.FeatureType#getNamespace()
360: // */
361: // public URI getNamespaceURI() {
362: // return featureType.getNamespaceURI();
363: // }
364:
365: /* (non-Javadoc)
366: * @see org.geotools.feature.FeatureType#getTypeName()
367: */
368: public String getTypeName() {
369: return featureType.getTypeName();
370: }
371:
372: /* (non-Javadoc)
373: * @see org.geotools.feature.FeatureType#getAttributeTypes()
374: */
375: public AttributeType[] getAttributeTypes() {
376: return featureType.getAttributeTypes();
377: }
378:
379: /* (non-Javadoc)
380: * @see org.geotools.feature.FeatureType#hasAttributeType(java.lang.String)
381: */
382: public boolean hasAttributeType(String xPath) {
383: return featureType.hasAttributeType(xPath);
384: }
385:
386: /* (non-Javadoc)
387: * @see org.geotools.feature.FeatureType#getAttributeType(java.lang.String)
388: */
389: public AttributeType getAttributeType(String xPath) {
390: return featureType.getAttributeType(xPath);
391: }
392:
393: /* (non-Javadoc)
394: * @see org.geotools.feature.FeatureType#find(org.geotools.feature.AttributeType)
395: */
396: public int find(AttributeType type) {
397: return featureType.find(type);
398: }
399:
400: /* (non-Javadoc)
401: * @see org.geotools.feature.FeatureType#getDefaultGeometry()
402: */
403: public GeometryAttributeType getDefaultGeometry() {
404: return featureType.getDefaultGeometry();
405: }
406:
407: /* (non-Javadoc)
408: * @see org.geotools.feature.FeatureType#getPrimaryGeometry()
409: */
410: public GeometryAttributeType getPrimaryGeometry() {
411: return featureType.getPrimaryGeometry();
412: }
413:
414: /* (non-Javadoc)
415: * @see org.geotools.feature.FeatureType#getAttributeCount()
416: */
417: public int getAttributeCount() {
418: return featureType.getAttributeCount();
419: }
420:
421: /* (non-Javadoc)
422: * @see org.geotools.feature.FeatureType#getAttributeType(int)
423: */
424: public AttributeType getAttributeType(int position) {
425: return featureType.getAttributeType(position);
426: }
427:
428: /* (non-Javadoc)
429: * @see org.geotools.feature.FeatureType#isDescendedFrom(java.lang.String, java.lang.String)
430: */
431: public boolean isDescendedFrom(URI nsURI, String typeName) {
432: return featureType.isDescendedFrom(nsURI, typeName);
433: }
434:
435: /* (non-Javadoc)
436: * @see org.geotools.feature.FeatureType#isDescendedFrom(org.geotools.feature.FeatureType)
437: */
438: public boolean isDescendedFrom(FeatureType type) {
439: return featureType.isDescendedFrom(type);
440: }
441:
442: /* (non-Javadoc)
443: * @see org.geotools.feature.FeatureType#isAbstract()
444: */
445: public boolean isAbstract() {
446: return featureType.isAbstract();
447: }
448:
449: /* (non-Javadoc)
450: * @see org.geotools.feature.FeatureType#getAncestors()
451: */
452: public FeatureType[] getAncestors() {
453: return featureType.getAncestors();
454: }
455:
456: /* (non-Javadoc)
457: * @see org.geotools.feature.FeatureType#duplicate(org.geotools.feature.Feature)
458: */
459: public Feature duplicate(Feature feature)
460: throws IllegalAttributeException {
461: return featureType.duplicate(feature);
462: }
463:
464: /* (non-Javadoc)
465: * @see org.geotools.feature.FeatureFactory#create(java.lang.Object[])
466: */
467: public Feature create(Object[] attributes)
468: throws IllegalAttributeException {
469: // Fixes GEOT-497
470: if ((attributes.length > 0) && (attributes[0] != null)) {
471: return create(attributes, attributes[0].toString());
472: } else
473: return featureType.create(attributes);
474: }
475:
476: /* (non-Javadoc)
477: * @see org.geotools.feature.FeatureFactory#create(java.lang.Object[], java.lang.String)
478: */
479: public Feature create(Object[] attributes, String featureID)
480: throws IllegalAttributeException {
481: return featureType.create(attributes, featureID);
482: }
483:
484: /**
485: * @return Returns the geometryFactory.
486: */
487: public VPFGeometryFactory getGeometryFactory() {
488: return geometryFactory;
489: }
490:
491: /* (non-Javadoc)
492: * @see org.geotools.feature.FeatureType#find(java.lang.String)
493: */
494: public int find(String attName) {
495: return featureType.find(attName);
496: }
497:
498: public boolean equals(Object obj) {
499: return featureType.equals(obj);
500: }
501:
502: public int hashCode() {
503: return featureType.hashCode();
504: }
505: }
|