/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2010, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.geojson.feature; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geojson.DelegatingHandler; import org.geotools.geojson.IContentHandler; import org.geotools.geojson.geom.GeometryCollectionHandler; import org.geotools.geojson.geom.GeometryHandler; import org.json.simple.parser.ParseException; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; /** * * * @source $URL$ */ public class FeatureHandler extends DelegatingHandler<SimpleFeature> { private int fid = 0; private String separator = "-"; String id; Geometry geometry; List<Object> values; List<String> properties; CoordinateReferenceSystem crs; SimpleFeatureBuilder builder; AttributeIO attio; SimpleFeature feature; private String baseId = "feature"; /** * should we attempt to automatically build fids */ private boolean autoFID = false; public FeatureHandler() { this(null, new DefaultAttributeIO()); } public FeatureHandler(SimpleFeatureBuilder builder, AttributeIO attio) { this.builder = builder; this.attio = attio; } @Override public boolean startObject() throws ParseException, IOException { if (properties == NULL_LIST) { properties = new ArrayList(); } else if (properties != null) { // start of a new object in properties means a geometry delegate = new GeometryHandler(new GeometryFactory()); } return super.startObject(); } public boolean startObjectEntry(String key) throws ParseException, IOException { if ("id".equals(key) && properties == null) { id = ""; return true; } else if ("crs".equals(key)) { delegate = new CRSHandler(); return true; } else if ("geometry".equals(key)) { delegate = new GeometryHandler(new GeometryFactory()); return true; } else if ("properties".equals(key) && delegate == NULL) { properties = NULL_LIST; values = new ArrayList(); } else if (properties != null && delegate == NULL) { properties.add(key); return true; } return super.startObjectEntry(key); } @Override public boolean startArray() throws ParseException, IOException { if (properties != null && delegate == NULL) { // array inside of properties delegate = new ArrayHandler(); } return super.startArray(); } @Override public boolean endArray() throws ParseException, IOException { if (delegate instanceof ArrayHandler) { super.endArray(); values.add(((ArrayHandler) delegate).getValue()); delegate = NULL; } return super.endArray(); } @Override public boolean endObject() throws ParseException, IOException { if (delegate instanceof IContentHandler) { ((IContentHandler) delegate).endObject(); if (delegate instanceof GeometryHandler) { Geometry g = ((IContentHandler<Geometry>) delegate).getValue(); if (g == null && ((GeometryHandler) delegate) .getDelegate() instanceof GeometryCollectionHandler) { // this means that the collecetion handler is still parsing objects, continue // to delegate to it } else { if (properties != null) { // this is a regular property values.add(g); } else { // its the default geometry geometry = g; } delegate = NULL; } } else if (delegate instanceof CRSHandler) { crs = ((CRSHandler) delegate).getValue(); delegate = UNINITIALIZED; } return true; } else if (delegate == UNINITIALIZED) { delegate = NULL; return true; } else if (properties != null) { if (builder == null) { // no builder specified, build on the fly builder = createBuilder(); } for (int i = 0; i < properties.size(); i++) { String att = properties.get(i); Object val = values.get(i); if (val instanceof String) { val = attio.parse(att, (String) val); } builder.set(att, val); } properties = null; values = null; return true; } else { feature = buildFeature(); id = null; geometry = null; properties = null; values = null; return true; } } @Override public boolean primitive(Object value) throws ParseException, IOException { if (delegate instanceof GeometryHandler && value == null) { delegate = NULL; return true; } else if ("".equals(id)) { id = value.toString(); setFID(id); return true; } else if (values != null && delegate == NULL) { // use the attribute parser values.add(value); return true; } return super.primitive(value); } @Override public SimpleFeature getValue() { return feature; } public CoordinateReferenceSystem getCRS() { return crs; } public void setCRS(CoordinateReferenceSystem crs) { this.crs = crs; } public void init() { feature = null; } SimpleFeatureBuilder createBuilder() { SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder(); typeBuilder.setName("feature"); typeBuilder.setNamespaceURI("http://geotools.org"); typeBuilder.setCRS(crs); if (properties != null) { for (int i = 0; i < properties.size(); i++) { String prop = properties.get(i); Object valu = values.get(i); typeBuilder.add(prop, valu != null ? valu.getClass() : Object.class); } } if (geometry != null) { addGeometryType(typeBuilder, geometry); } return new SimpleFeatureBuilder(typeBuilder.buildFeatureType()); } void addGeometryType(SimpleFeatureTypeBuilder typeBuilder, Geometry geometry) { typeBuilder.add("geometry", geometry != null ? geometry.getClass() : Geometry.class); typeBuilder.setDefaultGeometry("geometry"); } SimpleFeature buildFeature() { SimpleFeatureBuilder builder = this.builder != null ? this.builder : createBuilder(); SimpleFeatureType featureType = builder.getFeatureType(); SimpleFeature f = builder.buildFeature(getFID()); if (geometry != null) { if (featureType.getGeometryDescriptor() == null) { // GEOT-4293, case of geometry coming after properties, we have to retype // the builder // JD: this is ugly, we should really come up with a better way to store internal // state of properties, and avoid creating the builder after the properties object // is completed SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder(); typeBuilder.init(featureType); addGeometryType(typeBuilder, geometry); featureType = typeBuilder.buildFeatureType(); SimpleFeatureBuilder newBuilder = new SimpleFeatureBuilder(featureType); newBuilder.init(f); f = newBuilder.buildFeature(getFID()); } f.setAttribute(featureType.getGeometryDescriptor().getLocalName(), geometry); } incrementFID(); return f; } // "{" + // " 'type': 'Feature'," + // " 'geometry': {" + // " 'type': 'Point'," + // " 'coordinates': [" + val + "," + val + "]" + // " }, " + // "' properties': {" + // " 'int': 1," + // " 'double': " + (double)val + "," + // " 'string': '" + toString(val) + "'" + // " }," + // " 'id':'widgets." + val + "'" + // "}"; /** * set the ID to 0 */ private void resetFID() { fid = 0; } /** * Add one to the current ID */ private void incrementFID() { fid = fid + 1; } private void setFID(String f) { int index = f.lastIndexOf('.'); if (index < 0) { index = f.indexOf('-'); if (index >= 0) { separator = "-"; }else { autoFID = false; id = f; return; } } else { separator = "."; } baseId = f.substring(0, index); try { fid = Integer.parseInt(f.substring(index + 1)); } catch (NumberFormatException e) { autoFID = false; id = f; } } private String getFID() { if (id == null || autoFID) { return baseId + separator + fid; } else { return id; } } }