com.graphhopper.http.GraphHopperServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.graphhopper.http.GraphHopperServlet.java

Source

/*
 *  Licensed to GraphHopper and Peter Karich under one or more contributor
 *  license agreements. See the NOTICE file distributed with this work for 
 *  additional information regarding copyright ownership.
 * 
 *  GraphHopper 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.graphhopper.http;

import com.graphhopper.GHRequest;
import com.graphhopper.GraphHopper;
import com.graphhopper.GHResponse;
import com.graphhopper.routing.util.FlagEncoder;
import com.graphhopper.util.*;
import com.graphhopper.util.Helper;
import com.graphhopper.util.shapes.GHPoint;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static javax.servlet.http.HttpServletResponse.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * Servlet to use GraphHopper in a remote application (mobile or browser). Attention: If type is
 * json it returns the points in GeoJson format (longitude,latitude) unlike the format "lat,lon"
 * used otherwise.
 * <p/>
 * @author Peter Karich
 */
public class GraphHopperServlet extends GHBaseServlet {
    @Inject
    private GraphHopper hopper;

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        try {
            writePath(req, res);
        } catch (IllegalArgumentException ex) {
            writeError(res, SC_BAD_REQUEST, ex.getMessage());
        } catch (Exception ex) {
            logger.error("Error while executing request: " + req.getQueryString(), ex);
            writeError(res, SC_INTERNAL_SERVER_ERROR, "Problem occured:" + ex.getMessage());
        }
    }

    void writePath(HttpServletRequest req, HttpServletResponse res) throws Exception {
        List<GHPoint> infoPoints = getPoints(req);

        // we can reduce the path length based on the maximum differences to the original coordinates
        double minPathPrecision = getDoubleParam(req, "min_path_precision", 1d);
        boolean writeGPX = "gpx".equalsIgnoreCase(getParam(req, "type", "json"));
        boolean enableInstructions = writeGPX || getBooleanParam(req, "instructions", true);
        boolean calcPoints = getBooleanParam(req, "calc_points", true);
        boolean elevation = getBooleanParam(req, "elevation", false);
        String vehicleStr = getParam(req, "vehicle", "CAR").toUpperCase();
        String weighting = getParam(req, "weighting", "fastest");
        String algoStr = getParam(req, "algorithm", "");
        String localeStr = getParam(req, "locale", "en");

        StopWatch sw = new StopWatch().start();
        GHResponse rsp;
        if (!hopper.getEncodingManager().supports(vehicleStr)) {
            rsp = new GHResponse().addError(new IllegalArgumentException("Vehicle not supported: " + vehicleStr));
        } else if (elevation && !hopper.hasElevation()) {
            rsp = new GHResponse().addError(new IllegalArgumentException("Elevation not supported!"));
        } else {
            FlagEncoder algoVehicle = hopper.getEncodingManager().getEncoder(vehicleStr);
            rsp = hopper.route(new GHRequest(infoPoints).setVehicle(algoVehicle.toString()).setWeighting(weighting)
                    .setAlgorithm(algoStr).setLocale(localeStr).putHint("calcPoints", calcPoints)
                    .putHint("instructions", enableInstructions).putHint("douglas.minprecision", minPathPrecision));
        }

        float took = sw.stop().getSeconds();
        String infoStr = req.getRemoteAddr() + " " + req.getLocale() + " " + req.getHeader("User-Agent");
        PointList points = rsp.getPoints();
        String logStr = req.getQueryString() + " " + infoStr + " " + infoPoints + ", distance: " + rsp.getDistance()
                + ", time:" + Math.round(rsp.getMillis() / 60000f) + "min, points:" + points.getSize() + ", took:"
                + took + ", debug - " + rsp.getDebugInfo() + ", " + algoStr + ", " + weighting + ", " + vehicleStr;

        if (rsp.hasErrors())
            logger.error(logStr + ", errors:" + rsp.getErrors());
        else
            logger.info(logStr);

        if (writeGPX)
            writeGPX(req, res, rsp);
        else
            writeJson(req, res, rsp, took);
    }

    private void writeGPX(HttpServletRequest req, HttpServletResponse res, GHResponse rsp) throws Exception {
        boolean includeElevation = getBooleanParam(req, "elevation", false);
        res.setCharacterEncoding("UTF-8");
        res.setContentType("application/xml");
        String trackName = getParam(req, "track", "GraphHopper Track");
        res.setHeader("Content-Disposition", "attachment;filename=" + "GraphHopper.gpx");
        String timeZone = getParam(req, "timezone", "GMT");
        long time = getLongParam(req, "millis", System.currentTimeMillis());
        if (rsp.hasErrors())
            writeResponse(res, errorsToXML(rsp.getErrors()));
        else
            writeResponse(res, rsp.getInstructions().createGPX(trackName, time, timeZone, includeElevation));
    }

    String errorsToXML(List<Throwable> list) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.newDocument();
        Element gpxElement = doc.createElement("gpx");
        gpxElement.setAttribute("creator", "GraphHopper");
        gpxElement.setAttribute("version", "1.1");
        doc.appendChild(gpxElement);

        Element mdElement = doc.createElement("metadata");
        gpxElement.appendChild(mdElement);

        Element errorsElement = doc.createElement("extensions");
        mdElement.appendChild(errorsElement);

        for (Throwable t : list) {
            Element error = doc.createElement("error");
            errorsElement.appendChild(error);
            error.setAttribute("message", t.getMessage());
            error.setAttribute("details", t.getClass().getName());
        }
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        StringWriter writer = new StringWriter();
        transformer.transform(new DOMSource(doc), new StreamResult(writer));
        return writer.toString();
    }

    private void writeJson(HttpServletRequest req, HttpServletResponse res, GHResponse rsp, float took)
            throws JSONException, IOException {
        boolean enableInstructions = getBooleanParam(req, "instructions", true);
        boolean pointsEncoded = getBooleanParam(req, "points_encoded", true);
        boolean calcPoints = getBooleanParam(req, "calc_points", true);
        boolean includeElevation = getBooleanParam(req, "elevation", false);
        JSONObject json = new JSONObject();
        JSONObject jsonInfo = new JSONObject();
        json.put("info", jsonInfo);

        if (rsp.hasErrors()) {
            List<Map<String, String>> list = new ArrayList<Map<String, String>>();
            for (Throwable t : rsp.getErrors()) {
                Map<String, String> map = new HashMap<String, String>();
                map.put("message", t.getMessage());
                map.put("details", t.getClass().getName());
                list.add(map);
            }
            jsonInfo.put("errors", list);
        } else if (!rsp.isFound()) {
            Map<String, String> map = new HashMap<String, String>();
            map.put("message", "Not found");
            map.put("details", "");
            jsonInfo.put("errors", Collections.singletonList(map));
        } else {
            jsonInfo.put("took", Math.round(took * 1000));
            JSONObject jsonPath = new JSONObject();
            jsonPath.put("distance", Helper.round(rsp.getDistance(), 3));
            jsonPath.put("time", rsp.getMillis());

            if (calcPoints) {
                jsonPath.put("points_encoded", pointsEncoded);

                PointList points = rsp.getPoints();
                if (points.getSize() >= 2)
                    jsonPath.put("bbox", rsp.calcRouteBBox(hopper.getGraph().getBounds()).toGeoJson());

                jsonPath.put("points", createPoints(points, pointsEncoded, includeElevation));

                if (enableInstructions) {
                    InstructionList instructions = rsp.getInstructions();
                    jsonPath.put("instructions", instructions.createJson());
                }
            }
            json.put("paths", Collections.singletonList(jsonPath));
        }

        writeJson(req, res, json);
    }

    Object createPoints(PointList points, boolean pointsEncoded, boolean includeElevation) throws JSONException {
        if (pointsEncoded)
            return WebHelper.encodePolyline(points, includeElevation);

        JSONObject jsonPoints = new JSONObject();
        jsonPoints.put("type", "LineString");
        jsonPoints.put("coordinates", points.toGeoJson(includeElevation));
        return jsonPoints;
    }

    private List<GHPoint> getPoints(HttpServletRequest req) throws IOException {
        String[] pointsAsStr = getParams(req, "point");
        final List<GHPoint> infoPoints = new ArrayList<GHPoint>(pointsAsStr.length);
        for (int pointNo = 0; pointNo < pointsAsStr.length; pointNo++) {
            final String str = pointsAsStr[pointNo];
            String[] fromStrs = str.split(",");
            if (fromStrs.length == 2) {
                GHPoint place = GHPoint.parse(str);
                if (place != null)
                    infoPoints.add(place);
            }
        }

        return infoPoints;
    }
}