package com.c2c.controller; import static java.lang.Double.parseDouble; import static org.geotools.feature.simple.SimpleFeatureBuilder.build; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.geotools.data.Query; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.factory.CommonFactoryFinder; import org.geotools.factory.GeoTools; import org.geotools.feature.AttributeTypeBuilder; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureCollections; import org.geotools.feature.FeatureIterator; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geojson.feature.FeatureJSON; import org.geotools.geometry.jts.JTS; import org.geotools.referencing.CRS; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.filter.FilterFactory2; import org.opengis.filter.expression.PropertyName; import org.opengis.filter.spatial.Intersects; import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import com.c2c.data.DataQueryDimension; import com.c2c.data.DataQueryFeatureSource; import com.c2c.style.StyleGenerationParams; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; /** * The spring controller for obtaining the feature data of all the features * within a pixel of a returned map. A simplified geometry should be returned if * the geometry data is to be returned. This method is very related to GetData * and shares much of the same code. * * @author jeichar, pmauduit */ @Controller @RequestMapping("/getinfo") public class GetInfo extends AbstractQueryingController { private FeatureJSON JSON_ENCODER = new FeatureJSON(); private HashMap<String, String> indicatorsTable = null; @RequestMapping(method = RequestMethod.GET) public void getinfo(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "QUERYID") String queryId, @RequestParam(value = "STYLEID") String styleId, @RequestParam(value = "BBOX") String bbox, @RequestParam(value = "ATTRS", required = false) String attributes, @RequestParam(value = "SRS", required = false) String srs, @RequestParam(value = "TARGETSRS", required = false) String targetSrs, @RequestParam(value = "MAXFEATURES", required = false) Integer maxfeatures, @RequestParam(value = "FORMAT", required = false) String format) throws Exception { response.setContentType("application/json; charset=UTF-8"); final CoordinateReferenceSystem crs; if (srs == null) { crs = DefaultGeographicCRS.WGS84; } else { crs = CRS.decode(srs, true); } final int finalMaxFeatures; if (maxfeatures == null) { finalMaxFeatures = Integer.MAX_VALUE; } else { finalMaxFeatures = maxfeatures.intValue(); } DataQueryFeatureSource rs = getCache().getResults(queryId); SimpleFeatureSource results = (SimpleFeatureSource) rs.getFeatureSource(); ArrayList<String> dimKeys = new ArrayList<String>(); for (DataQueryDimension d : rs.getRows()) { dimKeys.add(d.getUniqueName()); } indicatorsTable = Util.lookupIndicators(rs); CoordinateReferenceSystem targetCrs = null; if (targetSrs != null) { targetCrs = CRS.decode(targetSrs, true); } /* lookup style */ StyleGenerationParams sld = getCache().getStyle(styleId); int numIndicators = 0; String[] attrs = null; String choroplethsIndicators = sld.getChoroplethsIndicator(); String[] overlayIndicators = sld.getOverlayIndicators(); if (overlayIndicators != null) { numIndicators += overlayIndicators.length + dimKeys.size(); } else { numIndicators += dimKeys.size(); } int currentIndex = 0; if (choroplethsIndicators != null) { numIndicators++; } attrs = new String[numIndicators]; if (overlayIndicators != null) { for (int i = 0; i < overlayIndicators.length; i++) { attrs[i] = overlayIndicators[i]; currentIndex++; } } if (choroplethsIndicators != null) { attrs[currentIndex] = choroplethsIndicators; currentIndex++; } for (int i = 0; i < dimKeys.size(); i++) { attrs[currentIndex + i] = dimKeys.get(i); } Query datastoreQuery = makeDatastoreQuery(bbox, results, finalMaxFeatures, attrs, crs, targetCrs); FeatureCollection<SimpleFeatureType, SimpleFeature> results2 = results.getFeatures(datastoreQuery); FeatureCollection<SimpleFeatureType, SimpleFeature> results3 = FeatureCollections.newCollection(); FeatureIterator<SimpleFeature> it = results2.features(); SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder(); typeBuilder.setName(results2.getSchema().getName()); Map<String,String> attNameMapping = new HashMap<String,String>(); AttributeTypeBuilder attBuilder = new AttributeTypeBuilder(); ArrayList<String> keptColumns = new ArrayList<String>(); for(AttributeDescriptor att : results2.getSchema().getAttributeDescriptors()) { String originalName = att.getLocalName(); if (dimKeys.contains(originalName)) continue; String humanReadable = readableName(originalName); attNameMapping.put(originalName, humanReadable); attBuilder.init(att); typeBuilder.add(attBuilder.buildDescriptor(humanReadable)); keptColumns.add(originalName); } /* adding specific column members */ typeBuilder.add("member", String.class); SimpleFeatureType renamedType = typeBuilder.buildFeatureType(); try { while (it.hasNext()) { SimpleFeature feature = it.next(); String membersColumnValue = ""; for (String curKey : dimKeys) { membersColumnValue += " " + feature.getAttribute(curKey); } membersColumnValue = membersColumnValue.trim(); ArrayList<Object> finalCols = new ArrayList<Object>(); for (String curKept : keptColumns) { finalCols.add(feature.getAttribute(curKept)); } SimpleFeature newFeature = build(renamedType, finalCols, feature.getID()); newFeature.setAttribute("member", membersColumnValue); results3.add(newFeature); } } finally { it.close(); } PrintWriter writer = response.getWriter(); try { response.setContentType("application/json"); JSON_ENCODER.writeFeatureCollection(results3, writer); } finally { writer.close(); } } private String readableName(String originalName) { String ret = null ; if (indicatorsTable != null) { ret = indicatorsTable.get(originalName); } // dimension_unique_name ? if (ret == null) { return originalName; } /* else */ return ret; } private Query makeDatastoreQuery(String _bbox, SimpleFeatureSource results, int finalMaxFeatures, String[] attributes, CoordinateReferenceSystem crs, CoordinateReferenceSystem targetCrs) throws FactoryException, TransformException { GeometryFactory fac = new GeometryFactory(); Geometry referenceGeom; String[] bbox = _bbox.split(","); double minx = parseDouble(bbox[0]); double miny = parseDouble(bbox[1]); double maxx = parseDouble(bbox[2]); double maxy = parseDouble(bbox[3]); Envelope env = new Envelope(minx, maxx, miny, maxy); referenceGeom = fac.toGeometry(env); final CoordinateReferenceSystem nativeCrs = results.getSchema().getGeometryDescriptor().getCoordinateReferenceSystem(); if (nativeCrs != null) { JTS.transform(referenceGeom, CRS.findMathTransform(crs, nativeCrs, true)); } final SimpleFeatureType schema = results.getSchema(); String geometryAttributeName = schema.getGeometryDescriptor().getLocalName(); FilterFactory2 filterFactory2 = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints()); final PropertyName geomAttribute = filterFactory2.property(geometryAttributeName); Intersects filter = filterFactory2.intersects(geomAttribute, filterFactory2.literal(referenceGeom)); if (attributes != null) { for (int i = 0; i < attributes.length; i++) { attributes[i] = attributes[i].trim(); } } final Query query = new Query(schema.getTypeName(), filter, attributes); query.setCoordinateSystemReproject(targetCrs); query.setMaxFeatures(finalMaxFeatures); return query; } }