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());
}
}