Models.Geographic.Repository.RepositoryGoogle.java Source code

Java tutorial

Introduction

Here is the source code for Models.Geographic.Repository.RepositoryGoogle.java

Source

/**
 * Copyright 2014 International Center for Tropical Agriculture (CIAT).
 * This file is part of:
 * Crop Wild Relatives
 * It is free software: You can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * at your option) any later version.
 * It is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * See <http://www.gnu.org/licenses/>.
 */

package Models.Geographic.Repository;

import Models.Geographic.Source.Location;
import Tools.Base64;
import Tools.Configuration;
import Tools.FixData;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 *
 * @author Steven Sotelo - stevenbetancurt@hotmail.com
 */
public class RepositoryGoogle {

    public final static String HEADER = "GOOGLE_group|GOOGLE_lat|GOOGLE_lon|GOOGLE_uncertain|GOOGLE_text|GOOGLE_value|";

    private static HashMap db;
    private static Mac mac;

    /**
     * Create a string URL with the corresponding signature code and client id.
     * @param path
     * @param query
     * @return the specified String URL
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws UnsupportedEncodingException
     * @throws URISyntaxException
     */
    private static String signRequest(String path, String query) throws NoSuchAlgorithmException,
            InvalidKeyException, UnsupportedEncodingException, URISyntaxException, IOException {
        if (RepositoryGoogle.mac == null) {
            // key
            byte[] key = Base64
                    .decode(Configuration.getParameter("geocoding_google_key").replace('-', '+').replace('_', '/'));
            // Get an HMAC-SHA1 signing key from the raw key bytes
            SecretKeySpec sha1Key = new SecretKeySpec(key, "HmacSHA1");
            // Get an HMAC-SHA1 Mac instance and initialize it with the HMAC-SHA1

            RepositoryGoogle.mac = Mac.getInstance("HmacSHA1");
            RepositoryGoogle.mac.init(sha1Key);
        }
        // Retrieve the proper URL components to sign
        String resource = path + '?' + query + "&client=" + Configuration.getParameter("geocoding_google_client");
        // compute the binary signature for the request
        byte[] sigBytes = RepositoryGoogle.mac.doFinal(resource.getBytes());
        // base 64 encode the binary signature
        String signature = Base64.encodeBytes(sigBytes);
        // convert the signature to 'web safe' base 64
        signature = signature.replace('+', '-').replace('/', '_');
        return resource + "&signature=" + signature;
    }

    /**
     * Method that geocoding a address from google api
     * @param country
     * @param adm1
     * @param adm2
     * @param adm3
     * @param local_area
     * @param locality
     * @return 
     */
    public static Location georenferencing(String country, String adm1, String adm2, String adm3, String local_area,
            String locality) {
        return RepositoryGoogle.georenferencing(country, adm1, adm2, adm3, local_area, locality,
                Double.parseDouble(Configuration.getParameter("geocoding_threshold")));
    }

    /**
     * Method that geocoding a address from google api
     * @param country
     * @param adm1
     * @param adm2
     * @param adm3
     * @param local_area
     * @param locality
     * @param uncertainty
     * @return 
     */
    public static Location georenferencing(String country, String adm1, String adm2, String adm3, String local_area,
            String locality, double uncertainty) {
        Location a = null;
        String key;
        try {
            key = FixData.generateKey(new String[] { country, adm1, adm2, adm3, local_area, locality });
            if (RepositoryGoogle.db == null)
                RepositoryGoogle.db = new HashMap();
            if (RepositoryGoogle.db.containsKey(key))
                return (Location) RepositoryGoogle.db.get(key);
            String data = (!locality.equals("") ? locality : "")
                    + (!local_area.equals("") ? local_area + "+,+" : "") + (!adm3.equals("") ? adm3 + "+,+" : "")
                    + (!adm2.equals("") ? adm2 + "+,+" : "") + (!adm1.equals("") ? adm1 + "+,+" : "")
                    + (!country.equals("") ? country + "+,+" : "");
            URL url = new URL(Configuration.getParameter("geocoding_google_url_send_xml") + "address="
                    + data.replace(" ", "%20").replace(".", "").replace(";", ""));
            URL file_url = new URL(
                    url.getProtocol() + "://" + url.getHost() + signRequest(url.getPath(), url.getQuery()));
            // Get information from URL
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            // Create a proxy to work in CIAT (erase this in another place)
            //Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy2.ciat.cgiar.org", 8080));
            DocumentBuilder db = dbf.newDocumentBuilder();
            //Document doc = db.parse(file_url.openConnection(proxy).getInputStream());
            Document doc = db.parse(file_url.openConnection().getInputStream());
            // Document with data
            if (doc != null) {
                NodeList locationList = doc.getElementsByTagName("location");
                NodeList locationTypeList = doc.getElementsByTagName("location_type");
                NodeList viewPortList = doc.getElementsByTagName("viewport");
                Node location = null, lat = null, lng = null;
                if (locationList.getLength() > 0) {
                    for (int i = 0; i < locationList.getLength(); i++) {
                        location = locationList.item(i);
                        if (location.hasChildNodes()) {
                            lat = location.getChildNodes().item(1);
                            lng = location.getChildNodes().item(3);
                        }
                    }
                    Node locationType = null;
                    if (locationTypeList.getLength() > 0) {
                        for (int i = 0; i < locationTypeList.getLength(); i++)
                            locationType = locationTypeList.item(i);
                    }
                    Node viewPort = null, northeast = null, southwest = null, lat_northeast = null,
                            lng_northeast = null, lat_southwest = null, lng_southwest = null;
                    if (viewPortList.getLength() > 0) {
                        for (int i = 0; i < viewPortList.getLength(); i++) {
                            viewPort = viewPortList.item(i);
                            if (viewPort.hasChildNodes()) {
                                northeast = viewPort.getChildNodes().item(1);
                                southwest = viewPort.getChildNodes().item(3);
                            }
                            /* Extract data from viewport field */
                            if (northeast.hasChildNodes()) {
                                lat_northeast = northeast.getChildNodes().item(1);
                                lng_northeast = northeast.getChildNodes().item(3);
                            }
                            if (southwest.hasChildNodes()) {
                                lat_southwest = southwest.getChildNodes().item(1);
                                lng_southwest = southwest.getChildNodes().item(3);
                            }
                        }
                    }
                    double[] coordValues = new double[] { Double.parseDouble(lat.getTextContent()),
                            Double.parseDouble(lng.getTextContent()) };
                    double[] coordValuesNortheast = new double[] {
                            Double.parseDouble(lat_northeast.getTextContent()),
                            Double.parseDouble(lng_northeast.getTextContent()) };
                    double[] coordValuesSouthwest = new double[] {
                            Double.parseDouble(lat_southwest.getTextContent()),
                            Double.parseDouble(lng_southwest.getTextContent()) };
                    double distance = FixData.getDistance(coordValuesNortheast, coordValuesSouthwest);
                    // Distance - km between Northeast and Southeast                    
                    if (distance <= uncertainty)
                        a = new Location(coordValues[0], coordValues[1], distance);
                    else {
                        RepositoryGoogle.db.put(key, a);
                        throw new Exception("Exceede uncertainty. " + "Uncertainty: " + distance + " THRESHOLD: "
                                + Configuration.getParameter("geocoding_threshold"));
                    }

                }
            }
            RepositoryGoogle.db.put(key, a);
        } catch (NoSuchAlgorithmException | InvalidKeyException | URISyntaxException | IOException
                | ParserConfigurationException | SAXException ex) {
            System.out.println(ex);
        } catch (Exception ex) {
            System.out.println(ex);
        }
        return a;
    }

    /**
     * 
     * @param latitude
     * @param longitude
     * @return 
     */
    public static HashMap reverse(double latitude, double longitude) {
        HashMap a = new HashMap();
        try {
            //URL url=new URL(Configuration.getParameter("geocoding_google_url_send_json") + "latlng=" + String.valueOf(latitude) + "," + String.valueOf(longitude));            
            URL url = new URL(Configuration.getParameter("geocoding_google_url_send_json") + "latlng="
                    + String.valueOf(latitude) + "," + String.valueOf(longitude));
            URL file_url = new URL(
                    url.getProtocol() + "://" + url.getHost() + signRequest(url.getPath(), url.getQuery()));
            //BufferedReader lector=new BufferedReader(new InputStreamReader(url.openStream()));
            BufferedReader lector = new BufferedReader(new InputStreamReader(file_url.openStream()));
            String textJson = "", tempJs;
            while ((tempJs = lector.readLine()) != null)
                textJson += tempJs;
            if (textJson == null)
                throw new Exception("Don't found item");
            JSONObject google = ((JSONObject) JSONValue.parse(textJson));
            a.put("status", google.get("status").toString());
            if (a.get("status").toString().equals("OK")) {
                JSONArray results = (JSONArray) google.get("results");
                JSONArray address_components = (JSONArray) ((JSONObject) results.get(2)).get("address_components");
                for (int i = 0; i < address_components.size(); i++) {
                    JSONObject items = (JSONObject) address_components.get(i);
                    //if(((JSONObject)types.get(0)).get("").toString().equals("country"))
                    if (items.get("types").toString().contains("country")) {
                        a.put("country", items.get("long_name").toString());
                        a.put("iso", items.get("short_name").toString());
                        break;
                    }
                }
            }
        } catch (Exception ex) {
            a = null;
            System.out.println("Error Google Geocoding: " + ex);
        }
        return a;
    }
}