org.emergya.osrm.OSRM.java Source code

Java tutorial

Introduction

Here is the source code for org.emergya.osrm.OSRM.java

Source

/*
 * Copyright (C) 2012, Emergya (http://www.emergya.com)
 *
 * @author <a href="mailto:marias@emergya.com">Mara Arias de Reyna</a>
 *
 * This file is part of GoFleetLS
 *
 * This software 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 2 of the License, or
 * (at your option) any later version.
 *
 * This software 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * As a special exception, if you link this library with other files to
 * produce an executable, this library does not by itself cause the
 * resulting executable to be covered by the GNU General Public License.
 * This exception does not however invalidate any other reasons why the
 * executable file might be covered by the GNU General Public License.
 */
package org.emergya.osrm;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.namespace.QName;

import net.opengis.gml.v_3_1_1.DirectPositionListType;
import net.opengis.gml.v_3_1_1.LineStringType;
import net.opengis.xls.v_1_2_0.AbstractResponseParametersType;
import net.opengis.xls.v_1_2_0.DetermineRouteRequestType;
import net.opengis.xls.v_1_2_0.DetermineRouteResponseType;
import net.opengis.xls.v_1_2_0.DistanceType;
import net.opengis.xls.v_1_2_0.DistanceUnitType;
import net.opengis.xls.v_1_2_0.RouteGeometryType;
import net.opengis.xls.v_1_2_0.RouteHandleType;
import net.opengis.xls.v_1_2_0.RouteInstructionType;
import net.opengis.xls.v_1_2_0.RouteInstructionsListType;
import net.opengis.xls.v_1_2_0.RouteSummaryType;
import net.opengis.xls.v_1_2_0.WayPointListType;
import net.opengis.xls.v_1_2_0.WayPointType;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.gofleet.internacionalization.I18n;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;

/**
 * @author marias
 * 
 */
@SuppressWarnings("restriction")
@Repository
public class OSRM {

    protected static final String EPSG_4326 = "EPSG:4326";
    private static Log LOG = LogFactory.getLog(OSRM.class);
    private GeometryFactory gf = new GeometryFactory();
    /*
     * Atribute to save tha last coordinate form a point in the line string
     * request
     */
    private Integer lastNode = null;
    private DatatypeFactory dataTypeFactory = new com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl();

    @Autowired
    private I18n i18n;

    /**
     * @param i18n
     *            the i18n to set
     */
    public void setI18n(I18n i18n) {
        this.i18n = i18n;
    }

    public OSRM() {
    }

    /**
     * To use outside spring context
     */
    public OSRM(I18n i18n) {
        this();
        setI18n(i18n);
    }

    /**
     * Route plan using osrm server.
     * 
     * @param param
     * @param host_port
     * @param http
     * @return
     * @throws IOException
     * @throws ParseException
     * @throws JAXBException
     * @throws InterruptedException
     */
    public AbstractResponseParametersType routePlan(DetermineRouteRequestType param, String host_port, String http,
            Locale locale) throws IOException, JAXBException, ParseException, InterruptedException {

        DetermineRouteResponseType res = new DetermineRouteResponseType();

        // MANDATORY:
        // Describes the overall characteristics of the route
        RouteSummaryType routeSummary = new RouteSummaryType();

        // OPTIONAL:
        // Contains a reference to the route stored at the Route
        // Determination Service server.
        // Can be used in subsequent request to the Route Service to request
        // additional information about the route, or to request an
        // alternate route.
        RouteHandleType routeHandle = new RouteHandleType();

        // Constains a list of turn-by-turn route instructions and advisories,
        // formatted for presentation.
        // May contain the geometry and bounding box if specified in the
        // request.
        // May contain description. FOr example this can be used to connect the
        // instruction with a map.
        RouteInstructionsListType routeInstructionsList = new RouteInstructionsListType();

        // RouteMapType: Contains a list of route maps.
        // Can be used to specify which type of map to be generated whether an
        // overview or maneuver.
        // May contain description. For example this can be used to connect the
        // instruction with a map.

        try {
            lastNode = null;
            RouteGeometryType routeGeometry = new RouteGeometryType();
            WayPointListType wayPointList = param.getRoutePlan().getWayPointList();

            String url = "/viaroute";

            CoordinateReferenceSystem sourceCRS = CRS.decode(EPSG_4326);
            CoordinateReferenceSystem targetCRS = GeoUtil.getSRS(wayPointList.getStartPoint());

            com.vividsolutions.jts.geom.Point point = GeoUtil.getPoint(wayPointList.getStartPoint(), sourceCRS);
            url += "?loc=" + point.getY() + "," + point.getX();

            for (WayPointType wayPoint : wayPointList.getViaPoint()) {
                point = GeoUtil.getPoint(wayPoint, sourceCRS);
                url += "&loc=" + point.getY() + "," + point.getX();
            }
            point = GeoUtil.getPoint(wayPointList.getEndPoint(), sourceCRS);
            url += "&loc=" + point.getY() + "," + point.getX();

            LOG.debug(url);

            LineStringType lst = new LineStringType();

            lst.setSrsName(targetCRS.getName().getCode());
            routeGeometry.setLineString(lst);
            res.setRouteGeometry(routeGeometry);

            JsonFactory f = new JsonFactory();
            JsonParser jp = f.createJsonParser(getOSRMStream(host_port, url));
            jp.nextToken();
            while (jp.nextToken() != JsonToken.END_OBJECT && jp.getCurrentToken() != null) {
                String fieldname = jp.getCurrentName();
                if (fieldname == null)
                    ;
                else if (jp.getCurrentName().equals("total_distance")) {
                    DistanceType duration = new DistanceType();
                    duration.setUom(DistanceUnitType.M);
                    duration.setValue(new BigDecimal(jp.getText()));
                    routeSummary.setTotalDistance(duration);
                } else if (jp.getCurrentName().equals("total_time")) {
                    Duration duration = dataTypeFactory.newDuration(true, 0, 0, 0, 0, 0, jp.getIntValue());
                    routeSummary.setTotalTime(duration);
                } else if (jp.getCurrentName().equals("route_geometry")) {
                    decodeRouteGeometry(lst.getPosOrPointPropertyOrPointRep(), targetCRS, sourceCRS, jp);
                } else if (jp.getCurrentName().equals("route_instructions")) {
                    processInstructions(locale, routeSummary, routeInstructionsList, jp, lst);
                }
                jp.nextToken();
            }
            jp.close(); // ensure resources get cleaned up timely and properly

            res.setRouteHandle(routeHandle);

            if (param.getRouteInstructionsRequest() != null) {
                res.setRouteInstructionsList(routeInstructionsList);
                res.getRouteInstructionsList().setFormat("text/plain");
                res.getRouteInstructionsList().setLang(locale.getLanguage());
            }
            res.setRouteSummary(routeSummary);
        } catch (Throwable t) {
            LOG.error("Error generating route response: " + t, t);
            t.printStackTrace();
        }

        return res;
    }

    private BufferedReader getOSRMStream(String host_port, String url) throws UnknownHostException, IOException {

        DefaultHttpClient httpclient = new DefaultHttpClient();
        HttpGet httpget = new HttpGet("http://" + host_port + url);

        HttpResponse response = httpclient.execute(httpget);

        BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        return in;
    }

    /**
     * @param locale
     * @param routeSummary
     * @param routeInstructionsList
     * @param jp
     * @throws IOException
     * @throws JsonParseException
     */
    public void processInstructions(Locale locale, RouteSummaryType routeSummary,
            RouteInstructionsListType routeInstructionsList, JsonParser jp, LineStringType lineString)
            throws IOException, JsonParseException {
        while (jp.nextToken() == JsonToken.START_ARRAY && jp.getCurrentToken() != null) {
            RouteInstructionType e = new RouteInstructionType();
            jp.nextToken();
            String instruction = jp.getText();
            if (i18n != null)
                instruction = i18n.getString(locale, jp.getText());
            jp.nextToken();
            if (jp.getText().length() > 0) {
                if (i18n == null)
                    instruction += " on " + jp.getText();
                else
                    instruction += " " + i18n.getString(locale, "on") + " " + jp.getText();
            }
            e.setInstruction(instruction);
            jp.nextToken();

            DistanceType distance = new DistanceType();
            distance.setUom(DistanceUnitType.M);
            distance.setValue(new BigDecimal(jp.getText()));
            e.setDistance(distance);

            // Get position
            jp.nextToken();
            Integer currentNode = null;
            if (routeInstructionsList.getRouteInstruction().size() > 0) {
                List<RouteInstructionType> lri = routeInstructionsList.getRouteInstruction();
                currentNode = jp.getIntValue();
                List<JAXBElement<?>> pointList = lineString.getPosOrPointPropertyOrPointRep();
                LineStringType lineToRoute = new LineStringType();
                if (currentNode > lastNode) {
                    List<JAXBElement<?>> pointListToRoute = new LinkedList<JAXBElement<?>>();
                    RouteGeometryType rgt = new RouteGeometryType();
                    for (int i = lastNode; i <= currentNode; i++) {
                        pointListToRoute.add(pointList.get(i));
                    }
                    lineToRoute.setPosOrPointPropertyOrPointRep(pointListToRoute);
                    rgt.setLineString(lineToRoute);
                    lri.get(lri.size() - 1).setRouteInstructionGeometry(rgt);
                }
            }
            lastNode = jp.getIntValue();

            jp.nextToken();

            Duration duration = dataTypeFactory.newDuration(true, 0, 0, 0, 0, 0, jp.getIntValue());
            e.setDuration(duration);

            while (jp.nextToken() != JsonToken.END_ARRAY && jp.getCurrentToken() != null)
                ;
            routeInstructionsList.getRouteInstruction().add(e);
        }
    }

    private List<JAXBElement<?>> decodeRouteGeometry(List<JAXBElement<?>> list, CoordinateReferenceSystem targetCRS,
            CoordinateReferenceSystem sourceCRS, JsonParser jp) throws NoSuchAuthorityCodeException,
            FactoryException, MismatchedDimensionException, TransformException, JsonParseException, IOException {

        MathTransform transform = null;

        LOG.trace(targetCRS.toWKT());
        LOG.trace(sourceCRS.toWKT());
        jp.nextToken();

        while (jp.nextToken() == JsonToken.START_ARRAY && jp.getCurrentToken() != null) {
            jp.nextToken();
            Double lat = jp.getDoubleValue();
            jp.nextToken();
            Double lon = jp.getDoubleValue();
            jp.nextToken();

            Coordinate coord = new Coordinate(lat, lon);
            Point sourceGeometry = gf.createPoint(coord);
            LOG.trace(sourceGeometry);
            if (sourceCRS != targetCRS) {
                if (transform == null)
                    transform = CRS.findMathTransform(sourceCRS, targetCRS);
                sourceGeometry = JTS.transform(sourceGeometry, transform).getCentroid();
                LOG.trace(sourceGeometry);
            }
            DirectPositionListType e = new DirectPositionListType();
            e.getValue().add(sourceGeometry.getY());
            e.getValue().add(sourceGeometry.getX());

            JAXBElement<DirectPositionListType> elem = new JAXBElement<DirectPositionListType>(
                    new QName("http://www.opengis.net/gml", "pos", "gml"), DirectPositionListType.class, e);

            list.add(elem);

        }

        return list;
    }
}