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

org.opentripplanner.geocoder.bano.BanoGeocoder Maven / Gradle / Ivy

package org.opentripplanner.geocoder.bano;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.locationtech.jts.geom.Envelope;
import org.geojson.Feature;
import org.geojson.FeatureCollection;
import org.geojson.GeoJsonObject;
import org.geojson.Point;
import org.opentripplanner.geocoder.Geocoder;
import org.opentripplanner.geocoder.GeocoderResult;
import org.opentripplanner.geocoder.GeocoderResults;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

/**
 * A geocoder using the data.gouv.fr API of BANO (Base Nationale d'Adresse Ouverte), the official
 * open-data address source covering the whole of France.
 *
 * The returned data is rather simple to use, as it returns a GeoJSON features collection.
 * 
 * Obviously, this geocoder will only work in France.
 *
 * @author laurent
 */
public class BanoGeocoder implements Geocoder {
    private static final Logger LOG = LoggerFactory.getLogger(BanoGeocoder.class);

    private static final String BANO_URL = "http://api-adresse.data.gouv.fr/search/";

    private static final int CLAMP_RESULTS = 10;

    private ObjectMapper mapper;

    public BanoGeocoder() {
        mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    /**
     */
    @Override
    public GeocoderResults geocode(String address, Envelope bbox) {

        try {
            URL banoUrl = getBanoGeocoderUrl(address, bbox);
            URLConnection conn = banoUrl.openConnection();
            InputStream in = conn.getInputStream();
            FeatureCollection featureCollection = mapper.readValue(in, FeatureCollection.class);
            in.close();

            List geocoderResults = new ArrayList();
            for (Feature feature : featureCollection.getFeatures()) {
                GeoJsonObject geom = feature.getGeometry();
                if (geom instanceof Point) {
                    Point p = (Point) geom;
                    GeocoderResult res = new GeocoderResult();
                    res.setLat(p.getCoordinates().getLatitude());
                    res.setLng(p.getCoordinates().getLongitude());
                    res.setDescription(feature.getProperties().get("label").toString());
                    /*
                     * Note: We also have here as properties a break-down of other details, such as
                     * the house number, street, city, postcode... Can be useful if needed.
                     */
                    geocoderResults.add(res);
                } else {
                    // Should not happen according to the API
                }
            }
            return new GeocoderResults(geocoderResults);

        } catch (IOException e) {
            LOG.error("Error processing BANO geocoder results", e);
            return new GeocoderResults(e.getLocalizedMessage());
        }
    }

    private URL getBanoGeocoderUrl(String address, Envelope bbox) throws IOException {
        UriBuilder uriBuilder = UriBuilder.fromUri(BANO_URL);
        uriBuilder.queryParam("q", address);
        uriBuilder.queryParam("limit", CLAMP_RESULTS);
        if (bbox != null) {
            uriBuilder.queryParam("lat", bbox.centre().y);
            uriBuilder.queryParam("lon", bbox.centre().x);
        }
        URI uri = uriBuilder.build();
        return new URL(uri.toString());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy