foam.nanos.geocode.GoogleMapsGeocodingDAO.java Source code

Java tutorial

Introduction

Here is the source code for foam.nanos.geocode.GoogleMapsGeocodingDAO.java

Source

/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

package foam.nanos.geocode;

import foam.core.ContextAgent;
import foam.core.FObject;
import foam.core.PropertyInfo;
import foam.core.X;
import foam.dao.DAO;
import foam.dao.ProxyDAO;
import foam.lib.json.JSONParser;
import foam.nanos.auth.Address;
import foam.nanos.pool.FixedThreadPool;
import foam.util.SafetyUtil;
import org.apache.commons.io.IOUtils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class GoogleMapsGeocodingDAO extends ProxyDAO {
    public static String API_HOST = "https://maps.googleapis.com/maps/api/geocode/json?address=";

    protected String apiKey_;
    protected PropertyInfo prop_;
    protected ThreadLocal<StringBuilder> sb = new ThreadLocal<StringBuilder>() {
        @Override
        protected StringBuilder initialValue() {
            return new StringBuilder();
        }

        @Override
        public StringBuilder get() {
            StringBuilder b = super.get();
            b.setLength(0);
            return b;
        }
    };

    public GoogleMapsGeocodingDAO(X x, String apiKey, PropertyInfo prop, DAO delegate) {
        setX(x);
        setDelegate(delegate);
        this.apiKey_ = apiKey;
        this.prop_ = prop;
    }

    @Override
    public FObject put_(X x, FObject obj) {
        final FObject result = super.put_(x, obj);

        ((FixedThreadPool) x.get("threadPool")).submit(x, new ContextAgent() {
            @Override
            public void execute(X x) {
                // don't geocode if no address property
                Address address = (Address) prop_.get(result);
                if (address == null) {
                    return;
                }

                // check if address updated
                if (address.getLatitude() != 0 && address.getLongitude() != 0) {
                    FObject stored = getDelegate().find(result.getProperty("id"));
                    if (stored != null && prop_.get(result) != null) {
                        Address storedAddress = (Address) prop_.get(result);
                        // compare fields that are used to populate Google maps query
                        if (SafetyUtil.compare(address.getAddress(), storedAddress.getAddress()) == 0
                                && SafetyUtil.compare(address.getCity(), storedAddress.getCity()) == 0
                                && SafetyUtil.compare(address.getRegionId(), storedAddress.getRegionId()) == 0
                                && SafetyUtil.compare(address.getPostalCode(), storedAddress.getPostalCode()) == 0
                                && SafetyUtil.compare(address.getCountryId(), storedAddress.getCountryId()) == 0) {
                            return;
                        }
                    }
                }

                StringBuilder builder = sb.get().append(API_HOST);
                // append address
                if (!SafetyUtil.isEmpty(address.getAddress())) {
                    builder.append(address.getAddress()).append(",");
                }

                // append city
                if (!SafetyUtil.isEmpty(address.getCity())) {
                    builder.append(address.getCity()).append(",");
                }

                // append province
                if (!SafetyUtil.isEmpty((String) address.getRegionId())) {
                    builder.append((String) address.getRegionId()).append(",");
                }

                // append postal code
                if (!SafetyUtil.isEmpty(address.getPostalCode())) {
                    builder.append(address.getPostalCode()).append(",");
                }

                // append country id
                if (!SafetyUtil.isEmpty((String) address.getCountryId())) {
                    builder.append((String) address.getCountryId());
                }

                // append api key
                builder.append("&key=").append(apiKey_);

                String line = null;
                HttpURLConnection conn = null;
                BufferedReader reader = null;

                try {
                    URL url = new URL(builder.toString().replace(" ", "+"));
                    conn = (HttpURLConnection) url.openConnection();
                    conn.setConnectTimeout(5 * 1000);
                    conn.setRequestMethod("GET");
                    conn.connect();

                    builder.setLength(0);
                    reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                    while ((line = reader.readLine()) != null) {
                        builder.append(line);
                    }

                    GoogleMapsGeocodeResponse response = (GoogleMapsGeocodeResponse) getX().create(JSONParser.class)
                            .parseString(builder.toString(), GoogleMapsGeocodeResponse.class);
                    if (response == null) {
                        throw new Exception("Invalid response");
                    }

                    if (!"OK".equals(response.getStatus())) {
                        throw new Exception(
                                !SafetyUtil.isEmpty(response.getError_message()) ? response.getError_message()
                                        : "Invalid response");
                    }

                    GoogleMapsGeocodeResult[] results = response.getResults();
                    if (results == null || results.length == 0) {
                        throw new Exception("Results not found");
                    }

                    GoogleMapsGeometry geometry = results[0].getGeometry();
                    if (geometry == null) {
                        throw new Exception("Unable to determine latitude and longitude");
                    }

                    GoogleMapsCoordinates coords = geometry.getLocation();
                    if (coords == null) {
                        throw new Exception("Unable to determine latitude and longitude");
                    }

                    // set latitude and longitude
                    address.setLatitude(coords.getLat());
                    address.setLongitude(coords.getLng());
                    prop_.set(result, address);
                    GoogleMapsGeocodingDAO.super.put_(x, result);
                } catch (Throwable ignored) {
                } finally {
                    IOUtils.closeQuietly(reader);
                    IOUtils.close(conn);
                }
            }
        });

        return result;
    }
}