All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.graphhopper.http.GraphHopperServlet Maven / Gradle / Ivy

/*
 *  Licensed to GraphHopper GmbH under one or more contributor
 *  license agreements. See the NOTICE file distributed with this work for 
 *  additional information regarding copyright ownership.
 * 
 *  GraphHopper GmbH 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.GHResponse;
import com.graphhopper.GraphHopperAPI;
import com.graphhopper.PathWrapper;
import com.graphhopper.routing.util.EncodingManager;
import com.graphhopper.routing.util.FlagEncoder;
import com.graphhopper.util.StopWatch;
import com.graphhopper.util.shapes.GHPoint;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import 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 java.io.IOException;
import java.io.StringWriter;
import java.util.*;

import static com.graphhopper.util.Parameters.DETAILS.PATH_DETAILS;
import static com.graphhopper.util.Parameters.Routing.*;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;

/**
 * Servlet to use GraphHopper in a remote client application like mobile or browser. Note: If type
 * is json it returns the points in GeoJson format (longitude,latitude) unlike the format "lat,lon"
 * used otherwise. See the full API response format in docs/web/api-doc.md
 * 

* * @author Peter Karich */ public class GraphHopperServlet extends GHBaseServlet { @Inject private GraphHopperAPI graphHopper; @Inject private EncodingManager encodingManager; @Inject private RouteSerializer routeSerializer; @Inject @Named("hasElevation") private boolean hasElevation; @Override public void doGet(HttpServletRequest httpReq, HttpServletResponse httpRes) throws ServletException, IOException { List requestPoints = getPoints(httpReq, "point"); GHResponse ghRsp = new GHResponse(); double minPathPrecision = getDoubleParam(httpReq, WAY_POINT_MAX_DISTANCE, 1d); boolean writeGPX = "gpx".equalsIgnoreCase(getParam(httpReq, "type", "json")); boolean enableInstructions = writeGPX || getBooleanParam(httpReq, INSTRUCTIONS, true); boolean calcPoints = getBooleanParam(httpReq, CALC_POINTS, true); boolean enableElevation = getBooleanParam(httpReq, "elevation", false); boolean pointsEncoded = getBooleanParam(httpReq, "points_encoded", true); String vehicleStr = getParam(httpReq, "vehicle", "car"); String weighting = getParam(httpReq, "weighting", "fastest"); String algoStr = getParam(httpReq, "algorithm", ""); String localeStr = getParam(httpReq, "locale", "en"); StopWatch sw = new StopWatch().start(); if (!ghRsp.hasErrors()) { try { if(requestPoints.isEmpty()){ throw new IllegalArgumentException("You have to pass at least one point"); } List favoredHeadings = Collections.EMPTY_LIST; try { favoredHeadings = getDoubleParamList(httpReq, "heading"); } catch (NumberFormatException e) { throw new IllegalArgumentException("heading list in wrong format: " + e.getMessage()); } if (!encodingManager.supports(vehicleStr)) { throw new IllegalArgumentException("Vehicle not supported: " + vehicleStr); } else if (enableElevation && !hasElevation) { throw new IllegalArgumentException("Elevation not supported!"); } else if (favoredHeadings.size() > 1 && favoredHeadings.size() != requestPoints.size()) { throw new IllegalArgumentException("The number of 'heading' parameters must be <= 1 " + "or equal to the number of points (" + requestPoints.size() + ")"); } List pointHints = Arrays.asList(getParams(httpReq, POINT_HINT)); if (pointHints.size() > 0 && pointHints.size() != requestPoints.size()) { throw new IllegalArgumentException("If you pass " + POINT_HINT + ", you need to pass a hint for every point, empty hints will be ignored"); } List pathDetails = Arrays.asList(getParams(httpReq, PATH_DETAILS)); FlagEncoder algoVehicle = encodingManager.getEncoder(vehicleStr); GHRequest request; if (favoredHeadings.size() > 0) { // if only one favored heading is specified take as start heading if (favoredHeadings.size() == 1) { List paddedHeadings = new ArrayList(Collections.nCopies(requestPoints.size(), Double.NaN)); paddedHeadings.set(0, favoredHeadings.get(0)); request = new GHRequest(requestPoints, paddedHeadings); } else { request = new GHRequest(requestPoints, favoredHeadings); } } else { request = new GHRequest(requestPoints); } initHints(request.getHints(), httpReq.getParameterMap()); request.setVehicle(algoVehicle.toString()). setWeighting(weighting). setAlgorithm(algoStr). setLocale(localeStr). setPointHints(pointHints). setPathDetails(pathDetails). getHints(). put(CALC_POINTS, calcPoints). put(INSTRUCTIONS, enableInstructions). put(WAY_POINT_MAX_DISTANCE, minPathPrecision); ghRsp = graphHopper.route(request); } catch (IllegalArgumentException ex) { ghRsp.addError(ex); } } float took = sw.stop().getSeconds(); String infoStr = httpReq.getRemoteAddr() + " " + httpReq.getLocale() + " " + httpReq.getHeader("User-Agent"); String logStr = httpReq.getQueryString() + " " + infoStr + " " + requestPoints + ", took:" + took + ", " + algoStr + ", " + weighting + ", " + vehicleStr; httpRes.setHeader("X-GH-Took", "" + Math.round(took * 1000)); int alternatives = ghRsp.getAll().size(); if (writeGPX && alternatives > 1) ghRsp.addError(new IllegalArgumentException("Alternatives are currently not yet supported for GPX")); if (ghRsp.hasErrors()) { logger.error(logStr + ", errors:" + ghRsp.getErrors()); } else { PathWrapper altRsp0 = ghRsp.getBest(); logger.info(logStr + ", alternatives: " + alternatives + ", distance0: " + altRsp0.getDistance() + ", time0: " + Math.round(altRsp0.getTime() / 60000f) + "min" + ", points0: " + altRsp0.getPoints().getSize() + ", debugInfo: " + ghRsp.getDebugInfo()); } if (writeGPX) { if (ghRsp.hasErrors()) { httpRes.setStatus(SC_BAD_REQUEST); httpRes.getWriter().append(errorsToXML(ghRsp.getErrors())); } else { // no error => we can now safely call getFirst String xml = createGPXString(httpReq, httpRes, ghRsp.getBest()); writeResponse(httpRes, xml); } } else { Map map = routeSerializer.toJSON(ghRsp, calcPoints, pointsEncoded, enableElevation, enableInstructions); Object infoMap = map.get("info"); if (infoMap != null) ((Map) infoMap).put("took", Math.round(took * 1000)); if (ghRsp.hasErrors()) writeJsonError(httpRes, SC_BAD_REQUEST, objectMapper.getNodeFactory().pojoNode(map)); else { writeJson(httpReq, httpRes, objectMapper.getNodeFactory().pojoNode(map)); } } } protected String createGPXString(HttpServletRequest req, HttpServletResponse res, PathWrapper rsp) { boolean includeElevation = getBooleanParam(req, "elevation", false); // default to false for the route part in next API version, see #437 boolean withRoute = getBooleanParam(req, "gpx.route", true); boolean withTrack = getBooleanParam(req, "gpx.track", true); boolean withWayPoints = getBooleanParam(req, "gpx.waypoints", false); res.setCharacterEncoding("UTF-8"); if ("application/xml".equals(req.getContentType())) res.setContentType("application/xml"); else res.setContentType("application/gpx+xml"); String trackName = getParam(req, "trackname", "GraphHopper Track"); res.setHeader("Content-Disposition", "attachment;filename=" + "GraphHopper.gpx"); long time = getLongParam(req, "millis", System.currentTimeMillis()); return rsp.getInstructions().createGPX(trackName, time, includeElevation, withRoute, withTrack, withWayPoints); } protected String errorsToXML(Collection list) { if (list.isEmpty()) throw new RuntimeException("errorsToXML should not be called with an empty list"); try { 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 extensionsElement = doc.createElement("extensions"); mdElement.appendChild(extensionsElement); Element messageElement = doc.createElement("message"); extensionsElement.appendChild(messageElement); messageElement.setTextContent(list.iterator().next().getMessage()); Element hintsElement = doc.createElement("hints"); extensionsElement.appendChild(hintsElement); for (Throwable t : list) { Element error = doc.createElement("error"); hintsElement.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(); } catch (Exception ex) { throw new RuntimeException(ex); } } protected List getPoints(HttpServletRequest req, String key) { String[] pointsAsStr = getParams(req, key); final List infoPoints = new ArrayList(pointsAsStr.length); for (String str : pointsAsStr) { String[] fromStrs = str.split(","); if (fromStrs.length == 2) { GHPoint point = GHPoint.parse(str); if (point != null) infoPoints.add(point); } } return infoPoints; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy