com.esri.gpt.server.openls.provider.services.geocode.GeocodeProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.esri.gpt.server.openls.provider.services.geocode.GeocodeProvider.java

Source

/* See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Esri Inc. licenses this file to You 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.
 */
package com.esri.gpt.server.openls.provider.services.geocode;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;

import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import com.esri.gpt.framework.util.Val;
import com.esri.gpt.server.csw.provider.components.ISupportedValues;
import com.esri.gpt.server.csw.provider.components.OwsException;
import com.esri.gpt.server.csw.provider.components.ParseHelper;
import com.esri.gpt.server.csw.provider.components.ServiceProperties;
import com.esri.gpt.server.csw.provider.components.ValidationHelper;
import com.esri.gpt.server.openls.provider.components.IOperationProvider;
import com.esri.gpt.server.openls.provider.components.IProviderFactory;
import com.esri.gpt.server.openls.provider.components.IResponseGenerator;
import com.esri.gpt.server.openls.provider.components.OperationContext;
import com.esri.gpt.server.openls.provider.components.XlsConstants;
import com.esri.gpt.server.openls.provider.util.Address;
import com.esri.gpt.server.openls.provider.util.GeocodedAddress;

/**
 * Provides the Openls Geocode operation.
 */
public class GeocodeProvider implements IOperationProvider {

    /**
     * class variables =========================================================
     */

    /** The Logger. */
    private static Logger LOGGER = Logger.getLogger(GeocodeProvider.class.getName());

    /**
     * constructors ============================================================
     */

    /** Default constructor */
    public GeocodeProvider() {
        super();
    }

    /**
     * methods =================================================================
     */

    /**
     * Handles a URL based request (HTTP GET).
     * 
     * @param context
     *            the operation context
     * @param request
     *            the HTTP request
     * @throws Exception
     *             if a processing exception occurs
     */
    public void handleGet(OperationContext context, HttpServletRequest request) throws Exception {

        // initialize
        LOGGER.finer("Handling Geocode request URL...");
        throw new OwsException("HTTP Get is not supported for this operation.");
    }

    /**
     * Handles an XML based request (normally HTTP POST).
     * 
     * @param context
     *            the operation context
     * @param root
     *            the root node
     * @param xpath
     *            an XPath to enable queries (properly configured with name
     *            spaces)
     * @throws Exception
     *             if a processing exception occurs
     */
    public void handleXML(OperationContext context, Node root, XPath xpath) throws Exception {

        // initialize
        LOGGER.finer("Handling Geocode request XML...");
        GeocodeParams tOptions = context.getRequestOptions().getGeocodeOptions();
        ServiceProperties svcProps = context.getServiceProperties();
        ParseHelper pHelper = new ParseHelper();
        ValidationHelper vHelper = new ValidationHelper();
        String locator;
        String[] parsed;
        ISupportedValues supported;

        // service and version are parsed by the parent RequestHandler

        // output format
        locator = "@outputFormat";
        parsed = pHelper.getParameterValues(root, xpath, locator);
        supported = svcProps.getSupportedValues(XlsConstants.Parameter_OutputFormat);
        context.getOperationResponse().setOutputFormat(vHelper.validateValue(supported, locator, parsed, false));

        // request ID
        locator = "@requestId";
        parsed = pHelper.getParameterValues(root, xpath, locator);
        tOptions.setRequestId(vHelper.validateValue(locator, parsed, false));

        GeocodeParams reqParams = new GeocodeParams();
        locator = "xls:GeocodeRequest";
        Node ndReq = (Node) xpath.evaluate(locator, root, XPathConstants.NODE);
        if (ndReq != null) {
            parseRequest(reqParams, ndReq, xpath);
        }

        try {
            context.getRequestOptions().getGeocodeOptions().setgAddrList(executeRequest(context, reqParams));

        } catch (Throwable e) {
            e.printStackTrace();
        }
        generateResponse(context);
    }

    /**
     * Reads Address Information from request
     * @param reqParams
     * @param ndReq
     * @param xpath
     * @throws XPathExpressionException
     */
    public void parseRequest(GeocodeParams reqParams, Node ndReq, XPath xpath) throws XPathExpressionException {
        NodeList ndAddresses = (NodeList) xpath.evaluate("xls:Address", ndReq, XPathConstants.NODESET);
        if (ndAddresses != null) {
            for (int i = 0; i < ndAddresses.getLength(); i++) {
                Node address = ndAddresses.item(i);
                if (address != null) {
                    Address addr = new Address();
                    Node ndStrAddr = (Node) xpath.evaluate("xls:StreetAddress", address, XPathConstants.NODE);
                    if (ndStrAddr != null) {
                        Node ndStr = (Node) xpath.evaluate("xls:Street", ndStrAddr, XPathConstants.NODE);
                        if (ndStr != null) {
                            addr.setStreet(ndStr.getTextContent());
                        }
                    }
                    Node ndPostalCode = (Node) xpath.evaluate("xls:PostalCode", address, XPathConstants.NODE);
                    if (ndPostalCode != null) {
                        addr.setPostalCode(ndPostalCode.getTextContent());
                    }
                    NodeList ndPlaces = (NodeList) xpath.evaluate("xls:Place", address, XPathConstants.NODESET);
                    if (ndPlaces != null) {
                        for (int j = 0; j < ndPlaces.getLength(); j++) {
                            Node ndPlace = ndPlaces.item(j);
                            String type = Val
                                    .chkStr((String) xpath.evaluate("@type", ndPlace, XPathConstants.STRING));
                            addr.setPlaceType(type);
                            if (type.equalsIgnoreCase("Municipality")) {
                                addr.setMunicipality(ndPlace.getTextContent());
                            } else if (type.equalsIgnoreCase("CountrySubdivision")) {
                                addr.setCountrySubdivision(ndPlace.getTextContent());
                            } else if (type.equalsIgnoreCase("BuildingNumber")) {
                                addr.setBuildingNumber(ndPlace.getTextContent());
                            } else if (type.equalsIgnoreCase("Intersection")) {
                                addr.setIntersection(ndPlace.getTextContent());
                            } else if (type.equalsIgnoreCase("StreetVec")) {
                                addr.setStreetVec(ndPlace.getTextContent());
                            }
                        }
                    }
                    reqParams.getAddresses().add(addr);
                }
            }
        }
    }

    /**
    * Generates the response.
    * @param context the operation context
    * @throws Exception if a processing exception occurs
    */
    private void generateResponse(OperationContext context) throws Exception {
        IProviderFactory factory = context.getProviderFactory();
        IResponseGenerator generator = factory.makeResponseGenerator(context);
        if (generator == null) {
            String msg = "IProviderFactory.makeResponseGenerator: instantiation failed.";
            LOGGER.log(Level.SEVERE, msg);
            throw new OwsException(msg);
        } else {
            generator.generateResponse(context);
        }
    }

    /**
    * Executes geocode request
    * @param context
    * @param params
    * @return
    * @throws Throwable
    */
    public ArrayList<GeocodedAddress> executeRequest(OperationContext context, GeocodeParams params)
            throws Throwable {

        String srvCfg = context.getRequestContext().getApplicationConfiguration().getCatalogConfiguration()
                .getParameters().getValue("openls.geocode");

        //   String m_srsName = params.getSrsName();
        if (params.getAddresses().size() <= 0) {
            Logger.getLogger("In processRequest: No address.");
        }
        InputStream is = null;
        for (int i = 0; i < params.getAddresses().size(); i++) {
            Address reqAddr = new Address();
            reqAddr = (Address) params.getAddresses().get(i);

            // MAKE THE GEOCODE REQUEST
            /*
             * http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_NA
             * /GeocodeServer
             * .../findAddressCandidates?Address=380+New+York+Street&City
             * =Redlands&State=CA& Zip=92373&Zip4=&Country=USA&outFields=&f=pjson
             */
            String sGeocodeRequest = makeGeocodeRequest(reqAddr);

            // SUBMIT THE REQUEST
            String sUrl = srvCfg + "/findAddressCandidates?" + sGeocodeRequest;
            LOGGER.info("REQUEST=\n" + sUrl);

            URL url = new URL(sUrl);
            URLConnection conn = url.openConnection();

            // Get the response
            String line = "";
            String sResponse = "";

            is = conn.getInputStream();

            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader rd = new BufferedReader(isr);
            while ((line = rd.readLine()) != null) {
                sResponse += line;
            }
            rd.close();
            url = null;

            return parseGeocodeResponse(sResponse);
        }

        return null;
    }

    /*
     * .../findAddressCandidates?Address=380+New+York+Street&City=Redlands&State=
     * CA & Zip=92373&Zip4=&Country=USA&outFields=&f=pjson
     */
    private String makeGeocodeRequest(Address reqAddr) {
        try {
            String sGeocodeRequest = "";

            sGeocodeRequest = "Address=" + java.net.URLEncoder.encode(reqAddr.getStreet(), "UTF-8");
            sGeocodeRequest += "&City=" + java.net.URLEncoder.encode(reqAddr.getMunicipality(), "UTF-8");
            sGeocodeRequest += "&State=" + java.net.URLEncoder.encode(reqAddr.getCountrySubdivision(), "UTF-8");
            sGeocodeRequest += "&Zip=" + java.net.URLEncoder.encode(reqAddr.getPostalCode(), "UTF-8");
            sGeocodeRequest += "&Country=" + java.net.URLEncoder.encode(reqAddr.getCountry(), "UTF-8");
            sGeocodeRequest += "&outFields=&f=json";

            return sGeocodeRequest;

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * Parses Geocode response
     * @param sResponse
     * @return
     * @throws Throwable
     */
    private ArrayList<GeocodedAddress> parseGeocodeResponse(String sResponse) throws Throwable {

        try {

            JSONObject jResponse = new JSONObject(sResponse);
            ArrayList<GeocodedAddress> gAddrList = new ArrayList<GeocodedAddress>();
            String xResponse = "<?xml version='1.0'?><response>" + org.json.XML.toString(jResponse) + "</response>";
            LOGGER.info("XML from JSON = " + xResponse);
            String addressName = "";

            Address respAddr = null;
            String street = "";
            String intStreet = "";
            String city = "";
            String state = "";
            String zip = "";
            String scoreStr = "";
            String x = "";
            String y = "";

            DocumentBuilderFactory xfactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = xfactory.newDocumentBuilder();
            InputSource inStream = new InputSource();
            inStream.setCharacterStream(new StringReader(xResponse));
            Document doc = db.parse(inStream);

            doc.getDocumentElement().normalize();
            LOGGER.info("Root element " + doc.getDocumentElement().getNodeName());
            NodeList nodeLst = doc.getElementsByTagName("candidates");
            LOGGER.info("Information of all candidates:");
            String country = "US";
            GeocodedAddress gAddr = null;
            for (int s = 0; s < nodeLst.getLength(); s++) {
                Node fstNode = nodeLst.item(s);
                gAddr = new GeocodedAddress();
                Element fstElmnt = (Element) fstNode;

                street = "";
                intStreet = "";
                city = "";
                state = "";
                zip = "";
                scoreStr = "";

                // LOCATION
                NodeList locationList = fstElmnt.getElementsByTagName("location");
                Element fstNmElmnt = (Element) locationList.item(0);
                NodeList nodeY = fstNmElmnt.getElementsByTagName("y");
                y = nodeY.item(0).getTextContent();
                LOGGER.info("y = " + y);
                NodeList nodeX = fstNmElmnt.getElementsByTagName("x");
                x = nodeX.item(0).getTextContent();
                LOGGER.info("x = " + x);

                gAddr.setCountry(country);
                gAddr.setX(x);
                gAddr.setY(y);

                // ADDRESS
                NodeList addressList = fstElmnt.getElementsByTagName("address");

                addressName = addressList.item(0).getTextContent();
                LOGGER.info("addressName = " + addressName);
                String[] addressParts = addressName.split(",");
                int count = 0;
                for (String addr : addressParts) {
                    count++;
                    if (count == 1) {
                        street = addr.trim();
                    } else if (count == 2) {
                        city = addr.trim();
                    } else if (count == 3) {
                        state = addr.trim();
                    } else if (count == 4) {
                        zip = addr.trim();
                    }
                }

                // SCORE
                NodeList scoreList = fstElmnt.getElementsByTagName("score");
                scoreStr = scoreList.item(0).getTextContent();
                LOGGER.info("score = " + scoreStr);

                // NOW ADD THIS RESULT TO THE OUTPUT pos
                respAddr = new Address();
                respAddr.setStreet(street);
                respAddr.setMunicipality(city);
                respAddr.setPostalCode(zip);
                respAddr.setCountrySubdivision(state);
                respAddr.setIntersection(intStreet);

                gAddr.setAddress(respAddr);
                gAddr.setScore(new Double(scoreStr));
                gAddrList.add(gAddr);
            }
            return gAddrList;
        } catch (Exception p_e) {
            Logger.getLogger("Caught Exception" + p_e.getLocalizedMessage());
        }
        return null;
    }

}