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: * Created on 13. april 2004, 14:35
017: */
018: package org.geotools.data.vpf;
019:
020: import java.io.File;
021: import java.io.IOException;
022: import java.sql.SQLException;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.Map;
026: import java.util.NoSuchElementException;
027:
028: import org.geotools.data.FeatureReader;
029: import org.geotools.data.vpf.file.VPFFile;
030: import org.geotools.data.vpf.file.VPFFileFactory;
031: import org.geotools.data.vpf.ifc.FCode;
032: import org.geotools.feature.AttributeType;
033: import org.geotools.feature.Feature;
034: import org.geotools.feature.FeatureType;
035: import org.geotools.feature.IllegalAttributeException;
036: import org.geotools.feature.type.AnnotationFeatureType;
037:
038: /**
039: *
040: * @author <a href="mailto:knuterik@onemap.org">Knut-Erik Johnsen</a>, Project OneMap
041: * @author Chris Holmes, Fulbright.
042: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/vpf/src/main/java/org/geotools/data/vpf/VPFFeatureReader.java $
043: */
044: public class VPFFeatureReader implements FeatureReader, FCode {
045: private boolean hasNext = true;
046: private boolean nextCalled = true;
047: private Feature currentFeature = null;
048: private final VPFFeatureType featureType;
049:
050: /** Creates a new instance of VPFFeatureReader */
051: public VPFFeatureReader(VPFFeatureType type) {
052: this .featureType = type;
053: }
054:
055: /* (non-Javadoc)
056: * @see org.geotools.data.FeatureReader#close()
057: */
058: public void close() throws IOException {
059: reset();
060: }
061:
062: /**
063: * Put together a map of VPF files and their corresponding
064: * TableRows
065: *
066: * @param file
067: * @param row
068: */
069: private Map generateFileRowMap(VPFFile file, Feature row)
070: throws IOException {
071: String tileFileName = null;
072: Map rows = new HashMap();
073: rows.put(file, row);
074: Iterator joinIter = featureType.getFeatureClass().getJoinList()
075: .iterator();
076: while (joinIter.hasNext()) {
077: ColumnPair columnPair = (ColumnPair) joinIter.next();
078: VPFFile primaryFile = getVPFFile(columnPair.column1);
079: VPFFile joinFile = null;
080: joinFile = getVPFFile(columnPair.column2);
081:
082: if (!rows.containsKey(joinFile)
083: && rows.containsKey(primaryFile)) {
084: Feature joinRow = (Feature) rows.get(primaryFile);
085:
086: try {
087: int joinID = Integer.parseInt(joinRow.getAttribute(
088: columnPair.column1.getName()).toString());
089: rows.put(joinFile, getVPFFile(columnPair.column2)
090: .getRowFromId(columnPair.column2.getName(),
091: joinID));
092: } catch (NullPointerException exc) {
093: // Non-matching joins - just put in a NULL
094: rows.put(joinFile, null);
095: } catch (IllegalAttributeException exc) {
096: // I really don't expect to see this one
097: exc.printStackTrace();
098: rows.put(joinFile, null);
099: }
100: }
101: }
102: return rows;
103:
104: }
105:
106: /* (non-Javadoc)
107: * @see org.geotools.data.FeatureReader#getFeatureType()
108: */
109: public FeatureType getFeatureType() {
110: return featureType;
111: }
112:
113: /* (non-Javadoc)
114: * @see org.geotools.data.FeatureReader#hasNext()
115: */
116: public boolean hasNext() throws IOException {
117: if (nextCalled) {
118: while (readNext())
119: ;
120: nextCalled = false;
121: }
122: return hasNext;
123: }
124:
125: /* (non-Javadoc)
126: * @see org.geotools.data.FeatureReader#next()
127: */
128: public Feature next() throws IOException,
129: IllegalAttributeException, NoSuchElementException {
130: nextCalled = true;
131: return currentFeature;
132: }
133:
134: /**
135: * Read a row and determine if it matches the feature type
136: * Three possibilities here:
137: * row is null -- hasNext = false, do not try again
138: * row matches -- hasNext = true, do not try again
139: * row does not match -- hasNext is undefined because we must try again
140: * @return Whether we need to read again
141: */
142: private boolean readNext() throws IOException {
143: boolean result = true;
144: VPFFile file = (VPFFile) featureType.getFeatureClass()
145: .getFileList().get(0);
146: hasNext = false;
147: Feature row = null;
148: try {
149: if (file.hasNext()) {
150: row = file.readFeature();
151: }
152: } catch (IOException exc1) {
153: // TODO Auto-generated catch block
154: exc1.printStackTrace();
155: } catch (IllegalAttributeException exc1) {
156: // TODO Auto-generated catch block
157: exc1.printStackTrace();
158: }
159: if ((row == null)) {
160: hasNext = false;
161: result = false;
162: }
163: // Exclude objects with a different FACC Code
164: else if (featureType.getFaccCode() != null) {
165: try {
166: Object temp = null;
167: for (int i = 0; temp == null
168: && i < ALLOWED_FCODE_ATTRIBUTES.length; i++) {
169: temp = row
170: .getAttribute(ALLOWED_FCODE_ATTRIBUTES[i]);
171: }
172: String faccCode = temp.toString().trim();
173: if (featureType.getFaccCode().equals(faccCode)) {
174: retrieveObject(file, row);
175: hasNext = true;
176: result = false;
177: }
178: } catch (RuntimeException exc) {
179: // Ignore this case because it typically means the f_code is invalid
180: }
181: }
182: return result;
183: }
184:
185: /**
186: * Get the values from all of the columns
187: * based on their presence (or absense) in the rows
188: *
189: * Potential cases:
190: * simple column
191: * join column
192: * non-matching join
193: * null value
194: * geometry
195: *
196: * @param file the file
197: * @param row the row
198: *
199: */
200: private void retrieveObject(VPFFile file, Feature row)
201: throws IOException {
202: VPFFile secondFile = null;
203: VPFColumn column = null;
204: Map rows = generateFileRowMap(file, row);
205: AttributeType[] attributes = featureType.getFeatureClass()
206: .getAttributeTypes();
207: Object[] values = new Object[featureType.getAttributeCount()];
208: Object value = null;
209: String featureId = null;
210: // Pass 1 - identify the feature identifier
211: for (int inx = 0; inx < attributes.length; inx++) {
212: // I am thinking it is probably safer to look this up
213: // by column name than by position, but if it breaks,
214: // it is easy enough to change
215: if (attributes[inx].getName().equals("id")) {
216: value = row.getAttribute(inx);
217: if (value != null) {
218: featureId = value.toString();
219: }
220: break;
221: }
222: }
223: try {
224: currentFeature = featureType.create(values, featureId);
225: } catch (IllegalAttributeException exc) {
226: // This shouldn't happen since everything should be nillable
227: exc.printStackTrace();
228: }
229:
230: // Pass 2 - get the attributes, including the geometry
231: for (int inx = 0; inx < attributes.length; inx++) {
232: try {
233: if (attributes[inx]
234: .getName()
235: .equals(
236: AnnotationFeatureType.ANNOTATION_ATTRIBUTE_NAME)) {
237: try {
238: //TODO: are we sure this is the intended action? Hard-coding an attribute to "nam"?
239: currentFeature.setAttribute(inx, "nam");
240: } catch (IllegalAttributeException exc) {
241: exc.printStackTrace();
242: }
243: continue;
244: }
245: column = (VPFColumn) attributes[inx];
246: value = null;
247: secondFile = getVPFFile(column);
248: Feature tempRow = (Feature) rows.get(secondFile);
249: if (tempRow != null) {
250: value = tempRow.getAttribute(column.getName());
251: if (column.isAttemptLookup()) {
252: try {
253: // Attempt to perform a lookup and conversion
254: String featureClassName = getVPFFile(column)
255: .getFileName();
256: String intVdtFileName = featureType
257: .getFeatureClass()
258: .getDirectoryName().concat(
259: File.separator).concat(
260: "int.vdt");
261: VPFFile intVdtFile = VPFFileFactory
262: .getInstance().getFile(
263: intVdtFileName);
264: Iterator intVdtIter = intVdtFile
265: .readAllRows().iterator();
266: while (intVdtIter.hasNext()) {
267: Feature intVdtRow = (Feature) intVdtIter
268: .next();
269: if (intVdtRow.getAttribute("table")
270: .toString().trim().equals(
271: featureClassName)
272: && (Short.parseShort(intVdtRow
273: .getAttribute("value")
274: .toString()) == Short
275: .parseShort(value
276: .toString()) && (intVdtRow
277: .getAttribute(
278: "attribute")
279: .toString().trim()
280: .equals(column
281: .getName())))) {
282: value = intVdtRow.getAttribute(
283: "description").toString()
284: .trim();
285: break;
286: }
287: }
288: // If there is a problem, forget about mapping and continue
289: } catch (IOException exc) {
290: } catch (RuntimeException exc) {
291: }
292: }
293: }
294: try {
295: currentFeature.setAttribute(inx, value);
296: } catch (ArrayIndexOutOfBoundsException exc) {
297: // TODO Auto-generated catch block
298: exc.printStackTrace();
299: } catch (IllegalAttributeException exc) {
300: // TODO Auto-generated catch block
301: exc.printStackTrace();
302: }
303: } catch (ClassCastException exc2) {
304: try {
305: // This is the area geometry case
306: featureType
307: .getFeatureClass()
308: .getGeometryFactory()
309: .createGeometry(featureType, currentFeature);
310: } catch (IllegalAttributeException exc) {
311: // TODO Auto-generated catch block
312: exc.printStackTrace();
313: } catch (SQLException exc) {
314: // TODO Auto-generated catch block
315: exc.printStackTrace();
316: }
317: }
318: }
319:
320: }
321:
322: /**
323: * Returns the VPFFile for a particular column.
324: * It will only find the first match, but that should be okay
325: * because duplicate columns will cause even bigger problems elsewhere.
326: * @param column the column to search for
327: * @return the VPFFile that owns this column
328: */
329: private VPFFile getVPFFile(AttributeType column) {
330: VPFFile result = null;
331: VPFFile temp;
332: Iterator iter = featureType.getFeatureClass().getFileList()
333: .iterator();
334: while (iter.hasNext()) {
335: temp = (VPFFile) iter.next();
336: if ((temp != null) && (temp.find(column) >= 0)) {
337: result = temp;
338: break;
339: }
340: }
341: return result;
342: }
343:
344: /**
345: * Need to reset the stream for the next time Resets the iterator by
346: * resetting the stream.
347: *
348: */
349: public void reset() {
350: VPFFile file = (VPFFile) featureType.getFeatureClass()
351: .getFileList().get(0);
352: file.reset();
353: VPFFileFactory.getInstance().reset();
354: }
355: }
|