/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.esri.gpt.control.georss;
import com.esri.gpt.framework.context.ApplicationConfiguration;
import com.esri.gpt.framework.context.ApplicationContext;
import com.esri.gpt.framework.geometry.Envelope;
import com.esri.gpt.framework.http.HttpClientException;
import com.esri.gpt.framework.http.HttpClientRequest;
import com.esri.gpt.framework.http.StringHandler;
import com.esri.gpt.framework.util.Val;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Geometry service.
*/
public class GeometryService {
private String geometryServiceURL;
/**
* Creates instance of the service object.
* @param URL URL to the service
*/
public GeometryService(String URL) {
this.geometryServiceURL = URL;
}
/**
* Creates instance as configured in gpt.xml.
* @return instance of the service
*/
public static GeometryService createDefaultInstance() {
ApplicationContext appCtx = ApplicationContext.getInstance();
ApplicationConfiguration appCfg = appCtx.getConfiguration();
return new GeometryService(appCfg.getInteractiveMap().getGeometryServiceUrl());
}
/**
* Performs projection.
* @param envelopes list of envelopes to project
* @param outSR output spatial reference (WKID)
* @return list of projected envelopes
* @throws JSONException if reading response as JSON fails
* @throws HttpClientException if HTTP communication fails
* @throws IOException if data transmission fails
*/
public List<Envelope> project(List<Envelope> envelopes, String outSR) throws JSONException, HttpClientException, IOException {
Envelope [] envArray = new Envelope[envelopes.size()];
Map<String,List<Envelope>> envMap = createEnvMap(envelopes, "4326");
for (Map.Entry<String,List<Envelope>> e: envMap.entrySet()) {
List<Envelope> inEnvs = e.getValue();
List<Envelope> outEnvs = inEnvs;
if (!e.getKey().equals(outSR)) {
outEnvs = project(inEnvs, e.getKey(), outSR);
}
for (int i=0; i<outEnvs.size() && i<inEnvs.size(); i++) {
int index = envelopes.indexOf(inEnvs.get(i));
if (index>=0) {
envArray[index] = outEnvs.get(i);
}
}
}
for (int i=0; i<envArray.length; i++) {
if (envArray[i]==null) {
envArray[i] = envelopes.get(i);
}
}
return Arrays.asList(envArray);
}
/**
* Performs projection.
* @param inEnv list of envelopes
* @param inSR input spatial reference (WKID)
* @param outSR output spatial reference (WKID)
* @return list of projected envelopes
* @throws JSONException if reading response as JSON fails
* @throws HttpClientException if HTTP communication fails
* @throws IOException if data transmission fails
*/
protected List<Envelope> project(List<Envelope> inEnv, String inSR, String outSR) throws JSONException, HttpClientException, IOException {
List<Envelope> outEnv = new ArrayList<Envelope>();
String geometries = envToJson(inEnv, inSR);
StringBuilder params = new StringBuilder();
params.append("f=").append("json");
params.append("&geometries=").append(enc(geometries));
params.append("&inSR=").append(inSR);
params.append("&outSR=").append(outSR);
HttpClientRequest request = new HttpClientRequest();
request.setUrl(geometryServiceURL+"/project?"+params);
StringHandler handler = new StringHandler();
request.setContentHandler(handler);
request.execute();
JSONObject response = new JSONObject(handler.getContent());
if (response.has("error")) {
JSONObject error = response.getJSONObject("error");
int code = error.getInt("code");
String message = error.getString("message");
throw new HttpClientException(code, message);
}
if (response.has("geometries")) {
JSONArray geoms = response.getJSONArray("geometries");
for (int i=0; i<geoms.length(); i++) {
JSONObject geom = geoms.getJSONObject(i);
outEnv.add(readEnvelope(geom));
}
}
return outEnv;
}
/**
* Read envelope from the JSON object.
* @param geom JSON object representing envelope
* @return envelope
* @throws JSONException if input object is not a valid envelope
*/
protected Envelope readEnvelope(JSONObject geom) throws JSONException {
double xmin = geom.getDouble("xmin");
double ymin = geom.getDouble("ymin");
double xmax = geom.getDouble("xmax");
double ymax = geom.getDouble("ymax");
Envelope env = new Envelope(xmin, ymin, xmax, ymax);
if (geom.has("spatialReference")) {
JSONObject sr = geom.getJSONObject("spatialReference");
String wkid = sr.getString("wkid");
env.setWkid(wkid);
}
return env;
}
/**
* Creates WKID to envelope mapping.
* @param envelopes envelopes
* @param defWkid default WKID
* @return mapping
*/
protected Map<String,List<Envelope>> createEnvMap(List<Envelope> envelopes, String defWkid) {
Map<String,List<Envelope>> envMap = new HashMap<String, List<Envelope>>();
for (Envelope env: envelopes) {
String wkid = Val.chkStr(env.getWkid(), defWkid);
List<Envelope> envList = envMap.get(wkid);
if (envList==null) {
envList = new ArrayList<Envelope>();
envMap.put(wkid, envList);
}
envList.add(env);
}
return envMap;
}
/**
* Turns list of envelopes into a JSON object.
* @param envList list of envelopes
* @param wkid WKID
* @return string representation of JSON object
*/
protected String envToJson(List<Envelope> envList, String wkid) {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"geometryType\":\"esriGeometryEnvelope\",");
sb.append("\"geometries\":");
sb.append("[");
StringBuilder sbEnv = new StringBuilder();
for (Envelope env: envList) {
if (sbEnv.length()>0) {
sbEnv.append(",");
}
sbEnv.append(envToJson(env, wkid));
}
sb.append(sbEnv);
sb.append("]");
sb.append("}");
return sb.toString();
}
/**
* Turns a single envelope into a JSON object.
* @param env envelope
* @param wkid WKID
* @return string representation of JSON object
*/
protected String envToJson(Envelope env, String wkid) {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"xmin\":").append(env.getMinX()).append(",");
sb.append("\"ymin\":").append(env.getMinY()).append(",");
sb.append("\"xmax\":").append(env.getMaxX()).append(",");
sb.append("\"ymax\":").append(env.getMaxY()).append(",");
sb.append("\"spatialReference\": { \"wkid\":").append(wkid).append("}");
sb.append("}");
return sb.toString();
}
/**
* Encodes a string.
* @param str string to encode
* @return encoded string
*/
protected String enc(String str) {
try {
return URLEncoder.encode(str, "UTF-8");
} catch (UnsupportedEncodingException ex) {
return str;
}
}
}