V1_0.java [src/java/m/example/gis_geotools] Revision: ddbe9454665107e4aeccb8b001af5ad651fa8371 Date: Mon Apr 11 15:41:56 MDT 2016
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package m.example.gis_geotools;
import com.vividsolutions.jts.geom.Geometry;
import csip.ModelDataService;
import csip.ServiceException;
import java.io.IOException;
import java.util.Map;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.SEVERE;
import javax.ws.rs.Path;
import oms3.annotations.Description;
import oms3.annotations.Name;
import static org.apache.commons.io.IOUtils.toInputStream;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeature;
/**
* Basic usage of the GeoTools Geometry and Feature objects.
* NOTE: This example also delves into:
* -- SQL statements for MsSQL -vs- PostGIS
* -- Demonstration, in the JSON example input files, of the _proper_ usage of "Geometry", "Feature" and "FeatureCollection" types.
* Notice in the basic_geometry JSON file there is no keyword "Geometry"...This is correct usage. "Geometry" is only specified in
* "Feature" or GeometryCollection, and has been misused, to date, in our service JSON examples .
* The FeatureCollection and Feature types in GeoJSON should be used to their utmost ability, if possible.
* Features that have properties should set those properties in their associated Feature properties section
* not specify them as separate JSONObjects in the input params. Using tools like ArcMap or ArcGIS can, subsequently
* produce the inputs for our services without outside intervention, if we utilize these GeoJSON features correctly.
* Please See: http://geojson.org/geojson-spec.html for further details...
* NOTE: Thus far, to date, our usage of "Feature" and "FeatureCollection" have been invalid GeoJSON in many cases, and this needs to be repaired,
* for instance, every "Feature" MUST have a "properties" section, but most of ours do not...and most of the time, we really mean
* to use "Geometry" not "Feature"....
*
*
* @author Shaun Case
*/
@Name("GIS_GeoTools")
@Description("An example of how to read in geometries or featurecollections using the geotools libraries. Also demonstrates proper GeoJSON, error passing with ModelDataServices and SQL differences between PostGIS and MsSQL")
@Path("m/gis_geotools/1.0")
public class V1_0 extends ModelDataService {
Geometry aoa_geometry;
JSONObject aoa_input_geometry;
String exampleQuery1, exampleQuery2, exampleQuery3, exampleQuery4;
@Override
// NOTE: Changed "Exception" to csip.ServiceException. (It's considered really bad form to throw a generic exception in Java)
// We will check the validity of the param array, if it is present, and return a distinct message identifying what is
// missing, if necessary, when we throw a csip.ServiceException. This is much better than just throwing the exception
// with no message at all.
protected void preProcess() throws csip.ServiceException {
Map<String, JSONObject> inputParams = getParamMap();
if (null != inputParams) {
this.aoa_input_geometry = inputParams.get("aoa_geometry");
if (null == this.aoa_input_geometry) {
throw new csip.ServiceException("No 'aoa_geometry' item was found in the JSON input. Please specify an 'aoa_geometry' .");
}
} else {
throw new csip.ServiceException("No JSON input parameters were found. Please specify some input.");
}
}
@Override
protected void doProcess() throws ServiceException {
GeometryJSON geoJSON = new GeometryJSON();
try {
if (this.aoa_input_geometry.has("features")) {
FeatureJSON featureJSON = new FeatureJSON();
FeatureCollection inputFeatures = featureJSON.readFeatureCollection(this.aoa_input_geometry.toString());
FeatureIterator tFeatures = inputFeatures.features();
int count = 1;
while (tFeatures.hasNext()) {
Feature tFeature = tFeatures.next();
this.aoa_geometry = (Geometry) ((SimpleFeature) tFeature).getAttribute("geometry");
LOG.log(INFO, "Feature geometry " + count + " recieved was: {0}", this.aoa_geometry.toText());
count++;
// Do something with this particular feature here...OR just grab the first one if only one was specified.
// This particular code assumes only one was specified, but can easily be altered to send more than one
// and do something with each....
}
} else {
if ( this.aoa_input_geometry.has("type")){ //Try to uncover if this is a "Feature" or a geometry object
if ( this.aoa_input_geometry.getString("type").equalsIgnoreCase("feature")){
FeatureJSON featureJSON = new FeatureJSON();
Feature tFeature = featureJSON.readFeature(this.aoa_input_geometry.toString());
this.aoa_geometry = (Geometry) ((SimpleFeature) tFeature).getAttribute("geometry");
// Here we could pull out the Feature's properies as well...
if ( LOG.isLoggable(INFO) ){
LOG.log(INFO, "This Feature''s Id is: {0}", ((SimpleFeature) tFeature).getID());
LOG.log(INFO, "This Feature''s name is: {0}", ((SimpleFeature) tFeature).getAttribute("name"));
//NOTE: For some reason, property values that are arrays (as in the example JSON), don't get read, so watch out for this!
LOG.log(INFO, "This Feature''s adjustment factor is: {0}", ((SimpleFeature) tFeature).getAttribute("AdjustmentFactor"));
}
}
else{ //Try to read the GeoJSON geometry object
this.aoa_geometry = geoJSON.read(toInputStream(this.aoa_input_geometry.toString()));
}
}
else{
}
}
// TODO: Add your code here to do something with the geometry(ies) you read in.
// For instance: See code lines below: (NOTE: The .toText() funciton of "Geometry" returns WKT..)
// Log the WKT of the input.
LOG.log(INFO, "Last aoa_geometry value recieved was: {0}", this.aoa_geometry.toText());
// PostGIS specific SQL statement below to calculate area in acres.
exampleQuery1 = "SELECT st_area(st_transform(ST_PolygonFromText('" + this.aoa_geometry.toText() + "', 4326),3541))/43560 as areaInAcres; ";
// MsSQL specific SQL statement below to calculate area in acres. (NOTE: Assumes point rotation is openGIS compliant, i.e. non-ESRI Shapefile)
exampleQuery2 = "SELECT geography::STGeomFromText('" + this.aoa_geometry.toText() + "', 4326).MakeValid().STArea() / 4046.86 as areaInAcres; ";
// MsSQL specific SQL statement below to calculate area in acres. (NOTE: Assumes point rotation is non-openGIS compliant, i.e. ESRI Shapefile)
exampleQuery3 = "SELECT geography::STGeomFromText('" + this.aoa_geometry.toText() + "', 4326).ReorientObject().MakeValid().STArea() / 4046.86 as areaInAcres; ";
// MsSQL specific SQL statement below to calculate area in acres. (NOTE: Example MsSQL Query for unkown rotation types using MsSQL CASE-WHEN Statement in-case rotation type is unknown.)
exampleQuery4 = "SELECT CASE WHEN geography::STGeomFromText('" + this.aoa_geometry.toText() + "', 4326).MakeValid().EnvelopeAngle() > 90 THEN geography::STGeomFromText('" + this.aoa_geometry.toText() + "', 4326).MakeValid().ReorientObject().STArea() ELSE geography::STGeomFromText('" + this.aoa_geometry.toText() + "', 4326).MakeValid().STArea() / 4046.86 END as areaInAcres; ";
} catch (IOException ex) {
LOG.log(SEVERE, "Cannot parse the input GeoJSON into valid GIS entities: ", ex);
throw new csip.ServiceException("Cannot parse the input GeoJSON into valid GIS entities: ",ex);
} catch (JSONException ex) {
LOG.log(SEVERE, "Cannot parse the aoa_geometry geometry type. Please check your syntax. ", ex);
throw new csip.ServiceException("Cannot parse the aoa_geometry geometry type. Please check your syntax. ", ex);
}
}
@Override
protected void postProcess(){
putResult("example_postgis_sql", exampleQuery1, "Example PostGIS SQL Query using input" );
putResult("example_mssql_sql_1", exampleQuery2, "Example MsSQL Query for ESRI Shapefile rotation using input" );
putResult("example_mssql_sql_2", exampleQuery3, "Example MsSQL Query for openGIS compliant rotation using input" );
putResult("example_mssql_sql_3", exampleQuery4, "Example MsSQL Query for unkown rotation types using MsSQL CASE-WHEN Statement" );
}
}