package com.esri.geoevent.solutions.processor.visibility;
/*
* #%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.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
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 org.apache.commons.logging.Log;
// import org.apache.commons.logging.LogFactory;
import com.esri.ges.framework.i18n.BundleLogger;
import com.esri.ges.framework.i18n.BundleLoggerFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.MapGeometry;
import com.esri.core.geometry.Point;
import com.esri.core.geometry.Polygon;
import com.esri.core.geometry.Polyline;
import com.esri.core.geometry.SpatialReference;
import com.esri.ges.core.ConfigurationException;
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.FieldException;
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.core.http.GeoEventHttpClient;
import com.esri.ges.core.http.GeoEventHttpClientService;
import com.esri.ges.core.validation.ValidationException;
import com.esri.ges.manager.geoeventdefinition.GeoEventDefinitionManager;
import com.esri.ges.manager.geoeventdefinition.GeoEventDefinitionManagerException;
import com.esri.ges.messaging.GeoEventCreator;
import com.esri.ges.messaging.Messaging;
import com.esri.ges.messaging.MessagingException;
import com.esri.ges.processor.GeoEventProcessorBase;
import com.esri.ges.processor.GeoEventProcessorDefinition;
public class VisibilityProcessor extends GeoEventProcessorBase {
// private static final Log LOG = LogFactory.getLog(VisibilityProcessor.class);
private static final BundleLogger LOG = BundleLoggerFactory.getLogger(VisibilityProcessor.class);
public GeoEventDefinitionManager manager;
private SpatialReference srIn;
private SpatialReference srBuffer;
private SpatialReference srOut;
private String outDefName;
private String gp;
private String is;
private String radiusSource;
private Boolean isRadiusConstant = false;
private Double radiusConstant;
private String radiusEventfld;
private String radiusUnit;
private String elevationSource;
private String elevEventfld;
private double elevConstant;
private Boolean isElevConstant=false;
private String units_elev;
private int outwkid;
private int procwkid;
private Messaging messaging;
private GeoEventHttpClientService httpClientService;
public VisibilityProcessor(GeoEventProcessorDefinition definition, GeoEventHttpClientService service)
throws ComponentException {
super(definition);
//manager = m;
//tagMgr=tm;
this.httpClientService = service;
geoEventMutator = true;
}
public void setMessaging(Messaging messaging)
{
this.messaging = messaging;
}
public void setManager(GeoEventDefinitionManager manager)
{
this.manager = manager;
}
@Override
public void afterPropertiesSet()
{
LOG.info("afterPropertiesSet starts.................");
outDefName = properties.get("outdefname").getValueAsString();
gp = properties.get("gpservice").getValue().toString();
is = properties.get("imageservice").getValue().toString();
radiusSource = properties.get("radiusSource").getValue().toString();
if(radiusSource.equals("Constant"))
{
isRadiusConstant=true;
radiusConstant = (Double) properties.get("radius").getValue();
}
else
{
radiusEventfld = properties.get("radiusEvent").getValue().toString();
}
radiusUnit = properties.get("units").getValue().toString();
elevationSource = properties.get("elevationSource").getValue().toString();
if(elevationSource.equals("Constant"))
{
isElevConstant=true;
elevConstant = (Double)properties.get("elevation").getValue();
}
units_elev = properties.get("units_elev").getValue().toString();
elevEventfld = properties.get("elevationEvent").getValue().toString();
outwkid = (Integer) properties.get("wkidout").getValue();
procwkid = (Integer) properties.get("wkidbuffer").getValue();
LOG.info("afterPropertiesSet ends.................");
}
@Override
public synchronized void validate() throws ValidationException
{
LOG.info("validate starts.................");
super.validate();
try
{
//srIn = SpatialReference.create(inwkid);
srBuffer = SpatialReference.create(procwkid);
srOut = SpatialReference.create(outwkid);
}
catch(Exception e)
{
ValidationException ve = new ValidationException("Invalid wkid");
LOG.error(e.getMessage());
LOG.error(ve.getMessage());
throw ve;
}
LOG.info("validate ends................");
}
@Override
public GeoEvent process(GeoEvent ge) throws Exception {
LOG.info("VisibilityProcessor.process starts.................");
double radius;
if(!ge.getGeoEventDefinition().getTagNames().contains("GEOMETRY"))
{
return null;
}
srIn=ge.getGeometry().getSpatialReference();
if(isRadiusConstant)
{
radius = radiusConstant;
}
else
{
radius = (Double)ge.getField(radiusEventfld);
}
double elevation;
if(isElevConstant){
elevation =elevConstant;
}
else
{
elevation = (Double)ge.getField(elevEventfld);
}
LOG.info("Calling ConstructVisibilityRest.................");
GeoEvent outGeo = ConstructVisibilityRest(ge, gp, is, radius, radiusUnit, elevation, units_elev, procwkid);
LOG.info("VisibilityProcessor.process ends.................");
return outGeo;
}
private GeoEvent ConstructVisibilityRest(GeoEvent ge, String gpservice, String imageservice, double range, String unit, double elevation, String units_elev, int wkid) throws UnsupportedEncodingException, IOException, ConfigurationException, FieldException, MessagingException, GeoEventDefinitionManagerException
{
LOG.info("Starting ConstructVisibilityRest.................");
UnitConverter uc = new UnitConverter();
range = uc.Convert(range, unit, srBuffer);
String procUnitName = srBuffer.getUnit().getName();
// normalize horizontal and vertical units to z-factor = 1
// double inElev = elevation;
if (procUnitName.equals("Meter")) {
if (units_elev.equals("Feet")) {
elevation = elevation * 0.3048;
}
} else {
if (units_elev.equals("Meters")) {
elevation = elevation * 3.28084;
}
}
MapGeometry eventGeo = ge.getGeometry();
Geometry tmpGeo = eventGeo.getGeometry();
Geometry projectedGeo = null;
if( srIn.getID() != procwkid )
{
projectedGeo = GeometryEngine.project(tmpGeo, srIn, srBuffer);
}
else
{
projectedGeo = tmpGeo;
}
Geometry mask = null;
if(tmpGeo.getType()==Geometry.Type.Polygon)
{
mask = projectedGeo;
}
else
{
mask = GeometryEngine.buffer(projectedGeo, srBuffer, range);
}
Envelope extent = new Envelope();
String obs = "";
if(properties.get("observerSource").getValueAsString().equals("Geoevent"))
{
mask.queryEnvelope(extent);
Double x = extent.getCenterX();
Double y = extent.getCenterY();
String cx = ((Double) x).toString();
String cy = ((Double) y).toString();
obs = cx + " " + cy;
}
else if(properties.get("observerSource").getValueAsString().equals("Field"))
{
String xeventfld = properties.get("observerXEvent").getValue().toString();
String[] arr = xeventfld.split(":");
Double x = (Double)ge.getField(arr[1]);
String yeventfld = properties.get("observerYEvent").getValue().toString();
arr = yeventfld.split(":");
Double y = (Double)ge.getField(arr[1]);
Point p = new Point(x,y);
p = (Point)GeometryEngine.project(p, srIn, srBuffer);
obs = ((Double)p.getX()).toString() + " " + ((Double)p.getY()).toString();
}
else
{
Double x = (Double)properties.get("observerX").getValue();
Double y = (Double)properties.get("observerY").getValue();
Point p = new Point(x,y);
p = (Point)GeometryEngine.project(p, srIn, srBuffer);
obs = ((Double)p.getX()).toString() + " " + ((Double)p.getY()).toString();
}
LOG.info("Got Values in ConstructVisibilityRest.................");
String contentType = "application/json";
GeoEventHttpClient http = httpClientService.createNewClient();
//HttpClient httpclient = HttpClientBuilder.create().build();
String observers = URLEncoder.encode(obs, "UTF-8");
imageservice = URLEncoder.encode(imageservice, "UTF-8");
String geoJson=GeometryEngine.geometryToJson(srBuffer, mask);
String jsonGeo = URLEncoder.encode(
geoJson, "UTF-8");
String args = "observers=" + observers + "&image_service_url="
+ imageservice + "&radius=" + ((Double) range).toString()
+ "&height=" + ((Double) elevation).toString() + "&json_mask="
+ jsonGeo + "&wkid=" + ((Integer) wkid).toString() + "&f=json";
String path = gpservice + "/execute?";
String uri = path + args;
MapGeometry visible = null;
MapGeometry nonvisible = null;
try {
HttpPost httppost = new HttpPost(uri);
httppost.setHeader("Accept", contentType);
CloseableHttpResponse response = http.execute(httppost, GeoEventHttpClient.DEFAULT_TIMEOUT);
//HttpResponse response = http.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;
}
ObjectMapper mapper = new ObjectMapper();
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>)mapper.readValue(output, new TypeReference<HashMap<String, Object>>(){});
@SuppressWarnings("unchecked")
ArrayList<Object> resString = (ArrayList<Object>)map.get("results");
@SuppressWarnings("unchecked")
Map<String, Object> r = (Map<String, Object>)resString.get(0);
@SuppressWarnings("unchecked")
Map<String,Object> fset = (Map<String,Object>)r.get("value");
//String fsetJson = mapper.writeValueAsString(val);
@SuppressWarnings("unchecked")
List<HashMap<String, Object>> features = (ArrayList<HashMap<String, Object>>)fset.get("features");
for (HashMap<String, Object> feature : features) {
@SuppressWarnings("unchecked")
HashMap<String, Object> attributes = (HashMap<String, Object>) feature.get("attributes");
int code = (Integer) attributes.get(
"gridcode");
// com.esri.ges.spatial.Geometry tmpgesVis = null;
// com.esri.ges.spatial.Geometry tmpgesNonVis =
// null;
if (code == 0) {
@SuppressWarnings("unchecked")
Map<String, Object> objGeo = (Map<String, Object>) feature.get("geometry");
Geometry tmpvis = generateGeoFromMap(objGeo);
Geometry vis = GeometryEngine.project(tmpvis,
srBuffer, srOut);
visible = new MapGeometry(vis, srOut);
} else {
@SuppressWarnings("unchecked")
Map<String, Object> objGeo = (Map<String, Object>) feature.get("geometry");
Geometry tmpnonvis=generateGeoFromMap(objGeo);
Geometry nonvis = GeometryEngine.project(
tmpnonvis, srBuffer, srOut);
nonvisible = new MapGeometry(nonvis, srOut);
}
}
} catch (IOException ex) {
// In case of an IOException the connection will be
// released
// back to the connection manager automatically
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.
httppost.abort();
throw ex;
} finally {
// Closing the input stream will trigger connection
// release
try {
instream.close();
} catch (Exception ignore) {
}
}
}
}
catch(Exception ex){
LOG.error("Exception in ConstructVisibilityRest: " + ex.getMessage());
return null;
}
GeoEventDefinition geoDef = ge.getGeoEventDefinition();
ArrayList<FieldDefinition> newFieldDefs = new ArrayList<FieldDefinition>();
FieldDefinition visFldDef = new DefaultFieldDefinition("visible", FieldType.Geometry, "GEOMETRY_VISIBLE");
FieldDefinition nonvisFldDef = new DefaultFieldDefinition("nonvisible", FieldType.Geometry, "GEOMETRY_NONVISIBLE");
newFieldDefs.add(visFldDef);
newFieldDefs.add(nonvisFldDef);
GeoEventDefinition edOut;
Collection<GeoEventDefinition>eventDefs = manager.searchGeoEventDefinitionByName(outDefName);
Iterator<GeoEventDefinition>eventDefIt = eventDefs.iterator();
while(eventDefIt.hasNext())
{
GeoEventDefinition currentDef = eventDefIt.next();
manager.deleteGeoEventDefinition(currentDef.getGuid());
}
edOut = geoDef.augment(newFieldDefs);
edOut.setOwner(getId());
edOut.setName(outDefName);
manager.addGeoEventDefinition(edOut);
GeoEventCreator geoEventCreator = messaging.createGeoEventCreator();
GeoEvent geOut = geoEventCreator.create(edOut.getGuid(), new Object[] {
ge.getAllFields(), visible, nonvisible });
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();
LOG.info("Ending ConstructVisibilityRest.................");
return geOut;
}
private String ConstructJsonMaskFromGeoEvent(GeoEvent ge) throws IOException
{
MapGeometry eventgeo = ge.getGeometry();
Geometry geo = eventgeo.getGeometry();
Geometry maskGeo = GeometryEngine.project(geo, srIn, srBuffer);
return GeometryEngine.geometryToJson(srBuffer, maskGeo);
}
private Geometry generateGeoFromMap(Map<String, Object> objGeo) throws Exception
{
Geometry geo = null;
if(objGeo.containsKey("rings"))
{
@SuppressWarnings("unchecked")
ArrayList<ArrayList<ArrayList<Object>>> rings= (ArrayList<ArrayList<ArrayList<Object>>>)objGeo.get("rings");
geo = generatePolygon(rings);
}
else if(objGeo.containsKey("paths"))
{
@SuppressWarnings("unchecked")
ArrayList<ArrayList<ArrayList<Object>>> paths= (ArrayList<ArrayList<ArrayList<Object>>>)objGeo.get("paths");
geo = generatePolyLine(paths);
}
else if(objGeo.containsKey("points"))
{
}
else
{
Double x = Double.valueOf(objGeo.get("x").toString());
Double y = Double.valueOf(objGeo.get("y").toString());
if(objGeo.size() > 2)
{
Double z = Double.valueOf(objGeo.get("z").toString());
geo = generate3DPoint(x,y,z);
}
else
{
geo = generatePoint(x,y);
}
}
return geo;
}
private Point generatePoint(Double x, Double y)
{
Point p = new Point(x, y);
return p;
}
private Point generate3DPoint(Double x, Double y, Double z)
{
Point p = new Point(x, y, z);
return p;
}
private Polyline generatePolyLine(ArrayList<ArrayList<ArrayList<Object>>> paths)
{
Polyline polyln = new Polyline();
for(ArrayList<ArrayList<Object>> path: paths)
{
Boolean firstPt = true;
for(ArrayList<Object> strPt: path)
{
Point p = null;
if(strPt.size() > 2)
{
Double x = (Double)strPt.get(0);
Double y = (Double)strPt.get(1);
Double z = (Double)strPt.get(2);
p = generate3DPoint(x,y,z);
}
else
{
Double x = (Double)strPt.get(0);
Double y = (Double)strPt.get(1);
p = generatePoint(x,y);
}
if(firstPt)
{
polyln.startPath(p);
firstPt = false;
}
else
{
polyln.lineTo(p);
}
}
}
return polyln;
}
private Polygon generatePolygon(ArrayList<ArrayList<ArrayList<Object>>> paths) throws Exception
{
try {
Polygon polygon = new Polygon();
for (ArrayList<ArrayList<Object>> path : paths) {
Boolean firstPt = true;
for (ArrayList<Object> strPt : path) {
Point p = null;
if (strPt.size() > 2) {
//String strY = strPt.get(1);
//String strZ = strPt.get(2);
Double x = (Double)strPt.get(0);
Double y = (Double)strPt.get(1);
Double z = (Double)strPt.get(2);
p = generate3DPoint(x, y, z);
} else {
Double x = (Double)strPt.get(0);
Double y = (Double)strPt.get(1);
p = generatePoint(x, y);
}
if (firstPt) {
polygon.startPath(p);
firstPt = false;
} else {
polygon.lineTo(p);
}
}
}
polygon.closeAllPaths();
return polygon;
} catch (Exception e) {
throw (e);
}
}
}