package ru.exorg.processing; import org.apache.commons.httpclient.HttpConnection; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpState; import org.apache.commons.httpclient.methods.GetMethod; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONValue; import org.springframework.beans.factory.InitializingBean; import ru.exorg.core.model.Location; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; final public class GeoService implements InitializingBean { final private static int httpPort = 80; final private static String GAPI_PROTO = "http://"; final private static String GAPI_SERVER = "maps.googleapis.com"; final private static String GAPI_PATH = "/maps/api/geocode/json?"; final private static String GAPI_Q_FOOTER = "&sensor=true"; final private static String YAPI_PROTO = "http://"; final private static String YAPI_SERVER = "geocode-maps.yandex.ru"; final private static String YAPI_PATH = "/1.x/?"; final private static String YAPI_Q_FOOTER = "&key=ANvK1k0BAAAAdOSwLAIAN1YUetQwuIkOfKscfc9OprS8ed8AAAAAAAAAAABpeUFMBr_TjUPQr01cqWYXU6dxUA==&format=json"; final public static int API_GOOGLE = 1; final public static int API_YANDEX = 2; private int timeout = 1000; private String proxyHost; private int proxyPort; private GoogleApi googleApi; private YandexApi yandexApi; private static JSONObject get(final JSONObject jobj, final String field) { return (JSONObject)jobj.get(field); } private interface GeoApi { public List<Location> queryLocation(final String address, final String guess) throws Exception; } private class YandexApi implements GeoApi { private JSONObject query(final String q) throws Exception { String res = queryHttp(YAPI_SERVER, YAPI_PATH, String.format("geocode=%s", URLEncoder.encode(q, "UTF-8")), YAPI_Q_FOOTER); //System.out.println(res); return (JSONObject)JSONValue.parse(res); } private List<Location> parse(final JSONObject gi) { if (gi == null) { return null; } JSONObject coll = get(get(gi, "response"), "GeoObjectCollection"); JSONObject response = get(get(coll, "metaDataProperty"), "GeocoderResponseMetaData"); if (!((String)response.get("found")).equals("0")) { JSONArray geoObjects = (JSONArray)coll.get("featureMember"); List<Location> r = new ArrayList<Location>(); for (int i = 0; i < geoObjects.size(); ++i) { JSONObject geoObject = get((JSONObject)geoObjects.get(i), "GeoObject"); //System.out.println(geoObject); String address = (String)get(get(geoObject, "metaDataProperty"), "GeocoderMetaData").get("text"); String[] pos = ((String)get(geoObject, "Point").get("pos")).split(" "); double lat = Double.parseDouble(pos[1]); double lng = Double.parseDouble(pos[0]); r.add(new Location(0, address, lat, lng)); } return r; } else { return null; } } public List<Location> queryLocation(final String address, final String guess) throws Exception { JSONObject r; if (address != null) { r = this.query(address); } else if (guess != null) { r = this.query(guess); } else { return null; } List<Location> locs = this.parse(r); if (locs == null && guess != null) { r = this.query(guess); locs = this.parse(r); } return locs; } } private class GoogleApi implements GeoApi { private JSONObject query(final String q) throws Exception { String res = queryHttp(GAPI_SERVER, GAPI_PATH, String.format("address=%s", URLEncoder.encode(q, "UTF-8")), GAPI_Q_FOOTER); return (JSONObject)JSONValue.parse(res); } private List<Location> parse(final JSONObject gi) { if (gi == null || gi.get("status") == null) { return null; } if (((String)gi.get("status")).equals("OK")) { List<Location> r = new ArrayList<Location>(); JSONArray results = (JSONArray)gi.get("results"); for (int i = 0; i < results.size(); ++i) { JSONObject first_res = (JSONObject)results.get(i); String address = (String)first_res.get("formatted_address"); JSONObject loc = (JSONObject)((JSONObject)first_res.get("geometry")).get("location"); double lat = ((Double)loc.get("lat")).doubleValue(); double lng = ((Double)loc.get("lng")).doubleValue(); r.add(new Location(0, address, lat, lng)); } return r; } else { return null; } } public List<Location> queryLocation(final String address, final String guess) throws Exception { JSONObject r; if (address != null) { r = this.query(address); } else if (guess != null) { r = this.query(guess); } else { return null; } List<Location> locs = parse(r); if (locs == null && guess != null) { r = this.query(guess); locs = parse(r); } return locs; } } private String queryHttp(final String server, final String servicePath, final String query, final String footer) throws Exception { HttpConnection conn = null; String hostName = server; String path = servicePath + query + footer; //System.out.println(path); HttpState state = new HttpState(); if (doesUseProxy()) { conn = new HttpConnection(proxyHost, proxyPort, hostName, httpPort); } else { conn = new HttpConnection(hostName, httpPort); } conn.open(); HttpMethod getMeth = new GetMethod(); getMeth.setPath(path); //getMeth.addRequestHeader("Host", "maps.googleapis.com"); getMeth.addRequestHeader("Accept", "application/json"); getMeth.addRequestHeader("User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US)"); //getMeth.addRequestHeader("Accept-Language", "ru"); getMeth.addRequestHeader("Accept-Language", "ru;en"); getMeth.addRequestHeader("Accept-Charset", "utf-8"); if (!doesUseProxy()) { getMeth.addRequestHeader("Connection", "close"); } else { getMeth.addRequestHeader("Proxy-Connection", "keep-alive"); } try { getMeth.execute(state, conn); } catch (Exception e) { throw e; } return new String(getMeth.getResponseBody()); } public void setProxy(final String proxy) { String[] proxyConf = proxy.split(":"); this.proxyHost = proxyConf[0]; this.proxyPort = Integer.parseInt(proxyConf[1]); } private boolean doesUseProxy() { return this.proxyHost != null; } public List<Location> lookupLocation(final Location loc, final String guess) throws Exception { List<Location> r; String address = loc.getAddress(); r = this.googleApi.queryLocation(address, guess); if (r == null) { r = this.yandexApi.queryLocation(address, guess); } return r; } public List<Location> lookupLocation(final Location loc, final String guess, int api) throws Exception { String address = loc.getAddress(); switch (api) { case API_GOOGLE: return this.googleApi.queryLocation(address, guess); case API_YANDEX: return this.yandexApi.queryLocation(address, guess); default: return null; } } public void afterPropertiesSet() { this.googleApi = new GoogleApi(); this.yandexApi = new YandexApi(); } }