package com.esri.geoevent.solutions.processor.geometry;
/*
* #%L
* Esri :: AGES :: Solutions :: Processor :: Geometry
* $Id:$
* $HeadURL:$
* %%
* Copyright (C) 2013 - 2014 Esri
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URL;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;
import org.joda.time.DateTime;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.LinearUnit;
import com.esri.core.geometry.MapGeometry;
import com.esri.core.geometry.Point;
import com.esri.core.geometry.Polygon;
import com.esri.core.geometry.SpatialReference;
import com.esri.core.geometry.Unit;
import com.esri.core.map.FeatureSet;
import com.esri.core.map.Graphic;
import com.esri.ges.core.component.ComponentException;
import com.esri.ges.core.geoevent.DefaultFieldDefinition;
import com.esri.ges.core.geoevent.FieldDefinition;
import com.esri.ges.core.geoevent.FieldType;
import com.esri.ges.core.geoevent.GeoEvent;
import com.esri.ges.core.geoevent.GeoEventDefinition;
import com.esri.ges.core.geoevent.GeoEventPropertyName;
import com.esri.ges.datastore.agsconnection.ArcGISServerConnection;
import com.esri.ges.datastore.agsconnection.ArcGISServerType;
import com.esri.ges.datastore.agsconnection.Field;
import com.esri.ges.datastore.agsconnection.Layer;
import com.esri.ges.manager.datastore.agsconnection.ArcGISServerConnectionManager;
import com.esri.ges.manager.geoeventdefinition.GeoEventDefinitionManager;
import com.esri.ges.messaging.GeoEventCreator;
import com.esri.ges.messaging.Messaging;
import com.esri.ges.processor.GeoEventProcessorBase;
import com.esri.ges.processor.GeoEventProcessorDefinition;
import com.esri.ges.spatial.Geometry;
import com.esri.ges.spatial.GeometryException;
import com.esri.ges.spatial.Spatial;
public class QueryReportProcessor extends GeoEventProcessorBase {
private static final Log LOG = LogFactory.getLog(RangeFanProcessor.class);
public Spatial spatial;
public GeoEventDefinitionManager manager;
public ArcGISServerConnectionManager connectionManager;
public Messaging messaging;
private SpatialReference srIn;
private SpatialReference srBuffer;
private SpatialReference srOut;
private ArrayList<Object>queries = new ArrayList<Object>();
private HashMap<String, Object>responseMap = new HashMap<String, Object>();
private com.esri.core.geometry.Geometry inGeometry;
public QueryReportProcessor(GeoEventProcessorDefinition definition, Spatial s, GeoEventDefinitionManager m, ArcGISServerConnectionManager cm, Messaging msg)
throws ComponentException {
super(definition);
spatial = s;
manager = m;
connectionManager = cm;
messaging = msg;
geoEventMutator= true;
}
//@Override
public void onServiceStop()
{
definition.getPropertyDefinitions().clear();
((QueryReportProcessorDefinition)definition).GenerateProperties();
}
@Override
public GeoEvent process(GeoEvent ge) throws Exception {
//CreateQueryMap();
CreateQueries();
double radius = (Double)properties.get("radius").getValue();
String units = properties.get("units").getValue().toString();
int inwkid = (Integer) properties.get("wkidin").getValue();
int outwkid = (Integer) properties.get("wkidout").getValue();
int bufferwkid = (Integer) properties.get("wkidbuffer").getValue();
srIn = SpatialReference.create(inwkid);
srBuffer = SpatialReference.create(bufferwkid);
srOut = SpatialReference.create(outwkid);
com.esri.ges.spatial.Geometry geo = ge.getGeometry();
com.esri.ges.spatial.Geometry inGeo = null;
if(properties.get("geosrc").getValueAsString().equals("Buffer"))
{
inGeometry = constructGeometry(geo);
Unit u = queryUnit(units);
inGeo = constructBuffer(geo,radius,u);
}
else if(properties.get("geosrc").getValueAsString().equals("Event Definition"))
{
String eventfld = properties.get("geoeventdef").getValue().toString();
String[] arr = eventfld.split(":");
String geostr = (String)ge.getField(arr[1]);
com.esri.ges.spatial.Geometry g = constructGeometryFromString(geostr);
com.esri.core.geometry.Geometry polyGeo= constructGeometry(g);
Envelope env = new Envelope();
polyGeo.queryEnvelope(env);
inGeometry = env.getCenter();
com.esri.core.geometry.Geometry projGeo = GeometryEngine.project(polyGeo, srBuffer, srOut);
String json = GeometryEngine.geometryToJson(srOut, projGeo);
inGeo = spatial.fromJson(json);
}
else
{
com.esri.core.geometry.Geometry polyGeo = constructGeometry(geo);
Envelope env = new Envelope();
polyGeo.queryEnvelope(env);
inGeometry = env.getCenter();
com.esri.core.geometry.Geometry projGeo = GeometryEngine.project(polyGeo, srBuffer, srOut);
String json = GeometryEngine.geometryToJson(srOut, projGeo);
inGeo = spatial.fromJson(json);
}
String jsonGeo = inGeo.toJson();
String geotype = GeometryUtility.parseGeometryType(inGeo.getType());
ExecuteRestQueries(jsonGeo, geotype);
String timestamp = "";
if((Boolean)properties.get("usetimestamp").getValue())
{
String eventfld = properties.get("timestamp").getValueAsString();
String[] arr = eventfld.split(":");
timestamp = ge.getField(arr[1]).toString();
}
DateTime dt = DateTime.now();
String ts = ((Integer) dt.getYear()).toString()
+ ((Integer) dt.getMonthOfYear()).toString()
+ ((Integer) dt.getDayOfMonth()).toString()
+ ((Integer) dt.getHourOfDay()).toString()
+ ((Integer) dt.getMinuteOfHour()).toString()
+ ((Integer) dt.getSecondOfMinute()).toString();
String file = properties.get("filename").getValueAsString() + ts + ".html";
ParseResponses(timestamp, file);
String host = properties.get("host").getValueAsString();
if(host.contains("http://"))
{
host.replace("http://", "");
}
String url = "http://" + host + ":6180/geoevent/assets/reports/" + file;
GeoEventDefinition geoDef = ge.getGeoEventDefinition();
String outDefName = geoDef.getName() + "_out";
GeoEventDefinition edOut;
if((edOut=manager.searchGeoEventDefinition(outDefName, getId()))==null)
{
List<FieldDefinition> fds = Arrays
.asList(((FieldDefinition) new DefaultFieldDefinition(
"url", FieldType.String)));
edOut = geoDef.augment(fds);
edOut.setOwner(getId());
edOut.setName(outDefName);
manager.addGeoEventDefinition(edOut);
}
GeoEventCreator geoEventCreator = messaging.createGeoEventCreator();
GeoEvent geOut = geoEventCreator.create(edOut.getGuid(), new Object[] {
ge.getAllFields(), url });
geOut.setProperty(GeoEventPropertyName.TYPE, "message");
geOut.setProperty(GeoEventPropertyName.OWNER_ID, getId());
geOut.setProperty(GeoEventPropertyName.OWNER_ID, definition.getUri());
for (Map.Entry<GeoEventPropertyName, Object> property : ge.getProperties())
if (!geOut.hasProperty(property.getKey()))
geOut.setProperty(property.getKey(), property.getValue());
queries.clear();
responseMap.clear();
return geOut;
}
private Unit queryUnit(String units)
{
UnitConverter uc = new UnitConverter();
String cn = uc.findConnonicalName(units);
int unitout = uc.findWkid(cn);
Unit u = new LinearUnit(unitout);
return u;
}
private com.esri.core.geometry.Geometry constructGeometry(com.esri.ges.spatial.Geometry geo) throws Exception
{
try{
String jsonIn = geo.toJson();
JsonFactory jf = new JsonFactory();
JsonParser jp = jf.createJsonParser(jsonIn);
MapGeometry mgeo = GeometryEngine.jsonToGeometry(jp);
com.esri.core.geometry.Geometry geoIn= mgeo.getGeometry();
return GeometryEngine.project(geoIn, srIn, srBuffer);
}
catch(Exception e)
{
LOG.error(e.getMessage());
LOG.error(e.getStackTrace());
throw(e);
}
}
private com.esri.ges.spatial.Geometry constructGeometryFromString(String geoString) throws GeometryException
{
String[] pairs = geoString.split(" ");
Polygon polygon = new Polygon();
Boolean firstit = true;
for(String coords: pairs)
{
String[] tuple = coords.split(",");
Double x = Double.parseDouble(tuple[0]);
Double y = Double.parseDouble(tuple[1]);
Point p = new Point(x,y);
Double z = Double.NaN;
if (tuple.length>2)
{
z = Double.parseDouble(tuple[2]);
p.setZ(z);
}
if(firstit)
{
polygon.startPath(p);
firstit=false;
}
else
{
polygon.lineTo(p);
}
}
polygon.closeAllPaths();
String json = GeometryEngine.geometryToJson(srIn, polygon);
return spatial.fromJson(json);
}
private com.esri.ges.spatial.Geometry constructBuffer(Geometry geo, double radius, Unit u) throws GeometryException, JsonParseException, IOException
{
com.esri.core.geometry.Geometry buffer = GeometryEngine.buffer(inGeometry, srBuffer, radius, u);
com.esri.core.geometry.Geometry bufferout = GeometryEngine.project(buffer, srBuffer, srOut);
String json = GeometryEngine.geometryToJson(srOut, bufferout);
return spatial.fromJson(json);
}
public void CreateQueries()
{
String connName = properties.get("connection").getValueAsString();
ArcGISServerConnection conn = connectionManager.getArcGISServerConnection(connName);
URL url = conn.getUrl();
String folder = properties.get("folder").getValueAsString();
String service = properties.get("service").getValueAsString();
String lyrName = properties.get("layer").getValueAsString();
Layer layer =conn.getLayer(folder, service, lyrName, ArcGISServerType.FeatureServer);
String layerId = ((Integer)layer.getId()).toString();
String field = properties.get("field").getValueAsString();
String baseUrl = url.getProtocol() +"://"+ url.getHost() + ":" + url.getPort()
+ url.getPath() + "rest/services/";
String curPath = baseUrl + "/" + folder + "/" + service + "/FeatureServer/" + layerId;
String restpath = curPath + "/query?";
HashMap<String, Object> query = new HashMap<String, Object>();
HashMap<String, String> fieldMap = new HashMap<String, String>();
String fldsString = field;
Field[] fields = conn.getFields(folder, service, layer.getId(), ArcGISServerType.FeatureServer);
Boolean usingDist=false;
String lyrHeaderCfg = "";
String distToken="";
String distUnits="";
String wc="";
String itemConfig = "";
wc = properties.get("wc")
.getValueAsString();
lyrHeaderCfg = properties.get("lyrheader").getValueAsString();
usingDist = (Boolean)properties.get("calcDistance").getValue();
if(usingDist)
{
distToken=properties.get("dist_token").getValueAsString();
distUnits=properties.get("dist_units").getValueAsString();
}
String token = properties.get("field-token")
.getValueAsString();
fieldMap.put(field, token);
itemConfig = properties.get("item-config").getValueAsString();
query.put("restpath", restpath);
query.put("path", curPath);
query.put("whereclause", wc);
query.put("fields", fldsString );
query.put("outfields", fields);
query.put("tokenMap", fieldMap);
query.put("headerconfig", lyrHeaderCfg);
query.put("usingdist", usingDist);
query.put("distunits", distUnits);
query.put("disttoken", distToken);
query.put("itemconfig", itemConfig);
query.put("layer", layer.getName());
UUID uid = UUID.randomUUID();
query.put("id", uid);
queries.add(query);
}
public void CreateQueryMap()
{
Collection<ArcGISServerConnection> serviceConnections = this.connectionManager
.getArcGISServerConnections();
Iterator<ArcGISServerConnection> it = serviceConnections.iterator();
ArcGISServerConnection conn;
while (it.hasNext()) {
conn = it.next();
//String connName = conn.getName();
String[] folders = conn.getFolders();
URL url = conn.getUrl();
String baseUrl = url.getProtocol() +"://"+ url.getHost() + ":" + url.getPort()
+ url.getPath() + "rest/services/";
//HashMap<String, Object> folderMap = new HashMap<String, Object>();
for (int i = 0; i < folders.length; ++i) {
String path = baseUrl + folders[i] + "/";
String folder = folders[i];
String[] fservices = conn.getFeatureServices(folder);
//HashMap<String,Object>serviceMap = new HashMap<String,Object>();
for (int j = 0; j < fservices.length; ++j) {
String fs = fservices[j];
path += fs + "/FeatureServer/";
String fqService = folder + "_" + fs;
String pdName = "use_" + fqService;
pdName=pdName.replace(" ", "_");
if ((Boolean) properties.get(pdName).getValue()) {
ArrayList<Layer> layers = (ArrayList<Layer>) conn
.getLayers(folder, fs,
ArcGISServerType.FeatureServer);
//HashMap<String, Object> layerMap = new HashMap<String, Object>();
for (int k = 0; k < layers.size(); ++k) {
HashMap<String, Object> query = new HashMap<String, Object>();
HashMap<String, String> fieldMap = new HashMap<String, String>();
String fldsString = "";
Field[] fields = conn.getFields(folder, fs, k, ArcGISServerType.FeatureServer);
Boolean usingDist=false;
String curPath="";
String restpath="";
String lyrHeaderCfg = "";
String distToken="";
String distUnits="";
String wc="";
String itemConfig = "";
String curLyr = layers.get(k).getName();
String lyrName = fqService + "_"
+ ((Integer) k).toString();
lyrName = lyrName.replace(" ", "_");
if ((Boolean) properties.get(lyrName).getValue()) {
curPath = path + ((Integer) k).toString();
restpath = path + ((Integer) k).toString() + "/query?";
wc = properties.get(lyrName + "_whereclause")
.getValueAsString();
lyrHeaderCfg = properties.get(lyrName + "_header").getValueAsString();
usingDist = (Boolean)properties.get(lyrName + "_calcDistance").getValue();
if(usingDist)
{
distToken=properties.get(lyrName + "_dist_token").getValueAsString();
distUnits=properties.get(lyrName + "_dist_units").getValueAsString();
}
itemConfig = properties.get(lyrName + "_config").getValueAsString();
Boolean first = true;
for (int l = 0; l < fields.length; ++l) {
String fld = fields[l].getName();
String fldPropName = lyrName + fld;
fldPropName = fldPropName.replace(" ", "_");
if ((Boolean) properties.get(fldPropName)
.getValue()) {
if (!first) {
fldsString += ",";
} else {
first = false;
}
fldsString += fld;
String fldToken = fldPropName
+ "_token";
String token = properties.get(fldToken)
.getValueAsString();
fieldMap.put(fld, token);
}
}
query.put("restpath", restpath);
query.put("path", curPath);
query.put("whereclause", wc);
query.put("fields", fldsString );
query.put("outfields", fields);
query.put("tokenMap", fieldMap);
query.put("headerconfig", lyrHeaderCfg);
query.put("usingdist", usingDist);
query.put("distunits", distUnits);
query.put("disttoken", distToken);
query.put("itemconfig", itemConfig);
query.put("layer", curLyr);
UUID uid = UUID.randomUUID();
query.put("id", uid);
queries.add(query);
//layerMap.put(layers.get(k).getName(), fieldMap);
}
}
}
}
//folderMap.put(folder, serviceMap);
}
//connmap.put(connName,folderMap);
}
}
private void ExecuteRestQueries(String jsonGeometry, String geoType)
throws GeometryException, UnsupportedEncodingException {
String contentType = "application/json";
HttpClient httpclient = new DefaultHttpClient();
for (int i = 0; i < queries.size(); ++i) {
@SuppressWarnings("unchecked")
HashMap<String, Object> query = (HashMap<String, Object>) queries
.get(i);
String path = (String) query.get("restpath");
String wc = URLEncoder.encode((String) query.get("whereclause"),
"UTF-8");
String geo = URLEncoder.encode(jsonGeometry, "UTF-8");
String fields = (String) query.get("fields");
@SuppressWarnings("unchecked")
HashMap<String, String> tokenMap = (HashMap<String, String>) query
.get("tokenMap");
String itemConfig = (String) query.get("itemconfig");
//
String args = "where="
+ wc
+ "&objectIds=&time=&geometry="
+ geo
+ "&geometryType="
+ geoType
+ "&inSR=&spatialRel=esriSpatialRelIntersects&relationParam=&outFields="
+ fields
+ "&returnGeometry=true&maxAllowableOffset=&geometryPrecision=&outSR=&gdbVersion=&returnDistinctValues=false&returnIdsOnly=false&returnCountOnly=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&returnZ=false&returnM=false&f=json";
String uri = path + args;
try {
HttpPost httppost = new HttpPost(uri);
httppost.setHeader("Accept", contentType);
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream = entity.getContent();
try {
// instream.read();
BufferedReader br = new BufferedReader(
new InputStreamReader((instream)));
String output = "";
String ln;
while ((ln = br.readLine()) != null) {
output += ln;
}
JsonFactory jf = new JsonFactory();
JsonParser jp = jf.createJsonParser(output);
FeatureSet fset = FeatureSet.fromJson(jp);
HashMap<String, Object> tuple = new HashMap<String, Object>();
String lyr = (String)query.get("layer");
String lyrheadercfg = (String)query.get("headerconfig");
Boolean calcdist = (Boolean)query.get("usingdist");
String distToken = (String)query.get("disttoken");
String distUnits = (String)query.get("distunits");
String id = query.get("id").toString();
tuple.put("fset", fset);
tuple.put("tokenmap", tokenMap);
tuple.put("config", itemConfig);
tuple.put("layer", lyr);
tuple.put("lyrheader", lyrheadercfg);
tuple.put("calcdist", calcdist);
tuple.put("distunits", distUnits);
tuple.put("disttoken", distToken);
responseMap.put(id, tuple);
} catch (IOException ex) {
// In case of an IOException the connection will be
// released
// back to the connection manager automatically
LOG.error(ex);
throw ex;
} catch (RuntimeException ex) {
// In case of an unexpected exception you may want to
// abort
// the HTTP request in order to shut down the underlying
// connection immediately.
LOG.error(ex);
httppost.abort();
throw ex;
} finally {
// Closing the input stream will trigger connection
// release
try {
instream.close();
} catch (Exception ignore) {
}
}
}
} catch (Exception ex) {
LOG.error(ex);
ex.printStackTrace();
}
}
}
private String GetDistAsString(Graphic g, SpatialReference inputSr, String units)
{
com.esri.core.geometry.Geometry geo = g.getGeometry();
com.esri.core.geometry.Geometry curGeo;
if(!inputSr.equals(srBuffer))
{
curGeo = GeometryEngine.project(geo, inputSr, srBuffer);
}
else
{
curGeo=geo;
}
double tmpDist = GeometryEngine.distance(inGeometry, curGeo, srBuffer);
UnitConverter uc = new UnitConverter();
int inUnitWkid = uc.findWkid(srBuffer.getUnit().getName());
String cn = uc.findConnonicalName(units);
int outUnitWkid = uc.findWkid(cn);
double dist;
if(inUnitWkid!=outUnitWkid)
{
dist = uc.Convert(tmpDist, inUnitWkid, outUnitWkid);
}
else
{
dist=tmpDist;
}
DecimalFormat df = new DecimalFormat("#.00");
return df.format(dist);
}
private void ParseResponses(String timestamp, String file)
{
Set<String> keys = responseMap.keySet();
Iterator<String> it = keys.iterator();
String body = "";
while(it.hasNext())
{
String k = it.next();
@SuppressWarnings("unchecked")
HashMap<String, Object> response = (HashMap<String, Object>) responseMap.get(k);
FeatureSet fset = (FeatureSet)response.get("fset");
String cfg = (String)response.get("config");
@SuppressWarnings("unchecked")
HashMap<String,Object>tokenmap=(HashMap<String, Object>)response.get("tokenmap");
String layer = (String)response.get("layer");
Graphic[] features = fset.getGraphics();
String lyrHeader = (String)response.get("lyrheader");
if(!lyrHeader.isEmpty())
{
lyrHeader = "<h3>"+lyrHeader+"</h3>";
}
String items = "";
items += "<b>"+layer.toUpperCase() + ": </b>";
Boolean usingDist = (Boolean)response.get("calcdist");
String distUnits = (String)response.get("distunits");
String distToken = (String)response.get("disttoken");
SpatialReference fsetSr = fset.getSpatialReference();
for (int i=0; i<features.length;++i)
{
Graphic f = features[i];
Map<String, Object> att = f.getAttributes();
Set<String> fields = tokenmap.keySet();
Iterator<String> itFields = fields.iterator();
String item = cfg;
if(usingDist)
{
String d = this.GetDistAsString(f, fsetSr, distUnits);
item = item.replace(distToken, d);
}
while(itFields.hasNext())
{
String fldname = itFields.next();
String token = (String) tokenmap.get(fldname);
item = item.replace(token, att.get(fldname).toString());
if(i>0)
{
items += ", ";
}
items += item;
}
}
items = "<p>"+items+"</p>";
body += lyrHeader + items;
}
String content = "";
//File file = new File("C:/Dev/Java/DefenseSolution/defense-geometry-processor/src/main/resources/ReportTemplate.html"); //for ex foo.txt
try {
//String name = this.getClass().getName();
InputStream is = this.getClass().getClassLoader().getResourceAsStream("ReportTemplate.html");
//FileInputStream is = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String ln;
while ((ln = br.readLine()) != null) {
content += ln;
}
String title = properties.get("title").getValueAsString();
String header = properties.get("header").getValueAsString();
if(!timestamp.isEmpty())
{
String tsToken = properties.get("timestamptoken").getValueAsString();
title = title.replace(tsToken, timestamp);
header = header.replace(tsToken, timestamp);
body = body.replace(tsToken, timestamp);
}
content = content.replace("[$TITLE]", "<h1>" +title+"</h1>");
content = content.replace("[$HEADING]", "<h2>" +header+"</h2>");
content = content.replace("[$BODY]", body);
br.close();
File dir = new File("assets/reports");
if(!dir.exists())
{
dir.mkdir();
}
String filename = "assets/reports/" + file;
File outfile = new File(filename);
FileOutputStream fos = new FileOutputStream(outfile);
OutputStreamWriter osw = new OutputStreamWriter(fos);
Writer w = new BufferedWriter(osw);
w.write(content);
w.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}