From 953852e6e984f8a639cf1a5ac4116fff755d538a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 7 May 2015 15:39:42 +1200 Subject: Add Gisgraphy reverse geocoder --- src/org/traccar/Context.java | 3 + src/org/traccar/ReverseGeocoderHandler.java | 7 ++- src/org/traccar/geocode/AddressFormat.java | 4 ++ .../traccar/geocode/GisgraphyReverseGeocoder.java | 67 ++++++++++++++++++++++ src/org/traccar/geocode/GoogleReverseGeocoder.java | 62 +++++++++++++------- .../traccar/geocode/NominatimReverseGeocoder.java | 49 +++++++++++++--- src/org/traccar/geocode/ReverseGeocoder.java | 2 +- .../traccar/geocode/GoogleReverseGeocoderTest.java | 19 ------ .../geocode/NominatimReverseGeocoderTest.java | 19 ------ test/org/traccar/geocode/ReverseGeocoderTest.java | 38 ++++++++++++ 10 files changed, 199 insertions(+), 71 deletions(-) create mode 100644 src/org/traccar/geocode/GisgraphyReverseGeocoder.java delete mode 100644 test/org/traccar/geocode/GoogleReverseGeocoderTest.java delete mode 100644 test/org/traccar/geocode/NominatimReverseGeocoderTest.java create mode 100644 test/org/traccar/geocode/ReverseGeocoderTest.java diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java index a180a64ab..ca45a34d6 100644 --- a/src/org/traccar/Context.java +++ b/src/org/traccar/Context.java @@ -17,6 +17,7 @@ package org.traccar; import org.traccar.database.DataCache; import org.traccar.database.DataManager; +import org.traccar.geocode.GisgraphyReverseGeocoder; import org.traccar.geocode.GoogleReverseGeocoder; import org.traccar.geocode.NominatimReverseGeocoder; import org.traccar.geocode.ReverseGeocoder; @@ -97,6 +98,8 @@ public class Context { String type = properties.getProperty("geocoder.type"); if (type != null && type.equals("nominatim")) { reverseGeocoder = new NominatimReverseGeocoder(properties.getProperty("geocoder.url")); + } if (type != null && type.equals("gisgraphy")) { + reverseGeocoder = new GisgraphyReverseGeocoder(properties.getProperty("geocoder.url")); } else { reverseGeocoder = new GoogleReverseGeocoder(); } diff --git a/src/org/traccar/ReverseGeocoderHandler.java b/src/org/traccar/ReverseGeocoderHandler.java index e48a11424..73254673c 100644 --- a/src/org/traccar/ReverseGeocoderHandler.java +++ b/src/org/traccar/ReverseGeocoderHandler.java @@ -19,6 +19,7 @@ import java.util.List; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; +import org.traccar.geocode.AddressFormat; import org.traccar.geocode.ReverseGeocoder; import org.traccar.model.Event; import org.traccar.model.Position; @@ -27,10 +28,12 @@ public class ReverseGeocoderHandler extends OneToOneDecoder { private final ReverseGeocoder geocoder; private final boolean processInvalidPositions; + private final AddressFormat addressFormat; public ReverseGeocoderHandler(ReverseGeocoder geocoder, boolean processInvalidPositions ) { this.geocoder = geocoder; this.processInvalidPositions = processInvalidPositions; + addressFormat = new AddressFormat(); } @Override @@ -44,14 +47,14 @@ public class ReverseGeocoderHandler extends OneToOneDecoder { if (processInvalidPositions || position.getValid()) { position.setAddress(geocoder.getAddress( - position.getLatitude(), position.getLongitude())); + addressFormat, position.getLatitude(), position.getLongitude())); } } else if (msg instanceof List) { List positions = (List) msg; for (Position position : positions) { if (processInvalidPositions || position.getValid()) { position.setAddress(geocoder.getAddress( - position.getLatitude(), position.getLongitude())); + addressFormat, position.getLatitude(), position.getLongitude())); } } } diff --git a/src/org/traccar/geocode/AddressFormat.java b/src/org/traccar/geocode/AddressFormat.java index 972326975..a90de8c5e 100644 --- a/src/org/traccar/geocode/AddressFormat.java +++ b/src/org/traccar/geocode/AddressFormat.java @@ -35,6 +35,10 @@ public class AddressFormat extends Format { private final String format; + public AddressFormat() { + this("%h %r, %t, %s, %c"); + } + public AddressFormat(String format) { this.format = format; } diff --git a/src/org/traccar/geocode/GisgraphyReverseGeocoder.java b/src/org/traccar/geocode/GisgraphyReverseGeocoder.java new file mode 100644 index 000000000..9d513a6f5 --- /dev/null +++ b/src/org/traccar/geocode/GisgraphyReverseGeocoder.java @@ -0,0 +1,67 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed 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 org.traccar.geocode; + +import org.traccar.helper.Log; + +import javax.json.Json; +import javax.json.JsonObject; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; + +public class GisgraphyReverseGeocoder implements ReverseGeocoder { + + private final String url; + + public GisgraphyReverseGeocoder() { + this("http://services.gisgraphy.com/street/streetsearch"); + } + + public GisgraphyReverseGeocoder(String url) { + this.url = url + "?format=json&lat=%f&lng=%f&from=1&to=1"; + } + + @Override + public String getAddress(AddressFormat format, double latitude, double longitude) { + + try { + Address address = new Address(); + URLConnection conn = new URL(String.format(url, latitude, longitude)).openConnection(); + + JsonObject json = Json.createReader(new InputStreamReader(conn.getInputStream())).readObject(); + JsonObject result = json.getJsonArray("result").getJsonObject(0); + + if (result.containsKey("name")) { + address.setStreet(result.getString("name")); + } + if (result.containsKey("isIn")) { + address.setSettlement(result.getString("isIn")); + } + if (result.containsKey("countryCode")) { + address.setCountry(result.getString("countryCode")); + } + + return format.format(address); + + } catch(Exception error) { + Log.warning(error); + } + + return null; + } + +} diff --git a/src/org/traccar/geocode/GoogleReverseGeocoder.java b/src/org/traccar/geocode/GoogleReverseGeocoder.java index 4ec6e10af..dae9915d8 100644 --- a/src/org/traccar/geocode/GoogleReverseGeocoder.java +++ b/src/org/traccar/geocode/GoogleReverseGeocoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2013 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2012 - 2015 Anton Tananaev (anton.tananaev@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,42 +15,62 @@ */ package org.traccar.geocode; -import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; -import java.nio.charset.Charset; import org.traccar.helper.Log; +import javax.json.*; + public class GoogleReverseGeocoder implements ReverseGeocoder { - private final static String MARKER = "\"formatted_address\" : \""; + private final String url = "http://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f"; @Override - public String getAddress(double latitude, double longitude) { + public String getAddress(AddressFormat format, double latitude, double longitude) { try { - URL url = new URL("http://maps.googleapis.com/maps/api/geocode/json?latlng=" + latitude + "," + longitude + "&sensor=false"); - URLConnection connection = url.openConnection(); - - connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),Charset.forName("UTF-8"))); - - // Find address line - String line; - while ((line = reader.readLine()) != null) { - int index = line.indexOf(MARKER); - if (index != -1) { - return line.substring(index + MARKER.length(), line.length() - 2); + Address address = new Address(); + URLConnection conn = new URL(String.format(url, latitude, longitude)).openConnection(); + + JsonObject json = Json.createReader(new InputStreamReader(conn.getInputStream())).readObject(); + JsonObject result = (JsonObject) json.getJsonArray("results").get(0); + JsonArray components = result.getJsonArray("address_components"); + + for (JsonObject component : components.getValuesAs(JsonObject.class)) { + + String value = component.getString("short_name"); + + for (JsonString type : component.getJsonArray("types").getValuesAs(JsonString.class)) { + if (type.getString().equals("street_number")) { + address.setHouse(value); + break; + } else if (type.getString().equals("route")) { + address.setStreet(value); + break; + } else if (type.getString().equals("locality")) { + address.setSettlement(value); + break; + } else if (type.getString().equals("administrative_area_level_2")) { + address.setDistrict(value); + break; + } else if (type.getString().equals("administrative_area_level_1")) { + address.setState(value); + break; + } else if (type.getString().equals("country")) { + address.setCountry(value); + break; + } else if (type.getString().equals("postal_code")) { + address.setPostcode(value); + break; + } } } - reader.close(); + return format.format(address); - } catch(IOException error) { + } catch(Exception error) { Log.warning(error); } diff --git a/src/org/traccar/geocode/NominatimReverseGeocoder.java b/src/org/traccar/geocode/NominatimReverseGeocoder.java index c9393da42..911e0fa71 100644 --- a/src/org/traccar/geocode/NominatimReverseGeocoder.java +++ b/src/org/traccar/geocode/NominatimReverseGeocoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2014 - 2015 Anton Tananaev (anton.tananaev@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,12 @@ */ package org.traccar.geocode; +import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; +import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonObject; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -26,23 +30,50 @@ import org.w3c.dom.Document; public class NominatimReverseGeocoder implements ReverseGeocoder { private final String url; + + public NominatimReverseGeocoder() { + this("http://nominatim.openstreetmap.org/reverse"); + } public NominatimReverseGeocoder(String url) { - this.url = url + "?format=xml&lat=%f&lon=%f&zoom=18&addressdetails=0"; + this.url = url + "?format=json&lat=%f&lon=%f&zoom=18&addressdetails=1"; } @Override - public String getAddress(double latitude, double longitude) { + public String getAddress(AddressFormat format, double latitude, double longitude) { try { - + Address address = new Address(); URLConnection conn = new URL(String.format(url, latitude, longitude)).openConnection(); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document doc = builder.parse(conn.getInputStream()); - - return doc.getFirstChild().getLastChild().getFirstChild().getNodeValue(); + JsonObject json = Json.createReader(new InputStreamReader(conn.getInputStream())).readObject().getJsonObject("address"); + + if (json.containsKey("house_number")) { + address.setHouse(json.getString("house_number")); + } + if (json.containsKey("road")) { + address.setStreet(json.getString("road")); + } + if (json.containsKey("village")) { + address.setSettlement(json.getString("village")); + } + if (json.containsKey("city")) { + address.setSettlement(json.getString("city")); + } + if (json.containsKey("state_district")) { + address.setDistrict(json.getString("state_district")); + } + if (json.containsKey("state")) { + address.setState(json.getString("state")); + } + if (json.containsKey("country_code")) { + address.setCountry(json.getString("country_code").toUpperCase()); + } + if (json.containsKey("postcode")) { + address.setPostcode(json.getString("postcode")); + } + + return format.format(address); } catch(Exception error) { Log.warning(error); diff --git a/src/org/traccar/geocode/ReverseGeocoder.java b/src/org/traccar/geocode/ReverseGeocoder.java index 67ce68ac2..b19a6b7ce 100644 --- a/src/org/traccar/geocode/ReverseGeocoder.java +++ b/src/org/traccar/geocode/ReverseGeocoder.java @@ -17,6 +17,6 @@ package org.traccar.geocode; public interface ReverseGeocoder { - public String getAddress(double latitude, double longitude); + public String getAddress(AddressFormat format, double latitude, double longitude); } diff --git a/test/org/traccar/geocode/GoogleReverseGeocoderTest.java b/test/org/traccar/geocode/GoogleReverseGeocoderTest.java deleted file mode 100644 index de1e182cc..000000000 --- a/test/org/traccar/geocode/GoogleReverseGeocoderTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.traccar.geocode; - -import static org.junit.Assert.assertEquals; -import org.junit.Test; - -public class GoogleReverseGeocoderTest { - - @Test - public void testGetAddress() { - - ReverseGeocoder reverseGeocoder = new GoogleReverseGeocoder(); - - /*assertEquals( - "ulitsa Morskiye dubki, 2, Lisy Nos, Saint Petersburg, Russia, 197755", - reverseGeocoder.getAddress(60.0, 30.0));*/ - - } - -} diff --git a/test/org/traccar/geocode/NominatimReverseGeocoderTest.java b/test/org/traccar/geocode/NominatimReverseGeocoderTest.java deleted file mode 100644 index 74e03f271..000000000 --- a/test/org/traccar/geocode/NominatimReverseGeocoderTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.traccar.geocode; - -import static org.junit.Assert.assertEquals; -import org.junit.Test; - -public class NominatimReverseGeocoderTest { - - @Test - public void testGetAddress() { - - ReverseGeocoder reverseGeocoder = new NominatimReverseGeocoder("http://nominatim.openstreetmap.org/reverse"); - - /*assertEquals( - "ulitsa Morskiye dubki, 2, Lisy Nos, Saint Petersburg, Russia, 197755", - reverseGeocoder.getAddress(60.0, 30.0));*/ - - } - -} diff --git a/test/org/traccar/geocode/ReverseGeocoderTest.java b/test/org/traccar/geocode/ReverseGeocoderTest.java new file mode 100644 index 000000000..6f244b545 --- /dev/null +++ b/test/org/traccar/geocode/ReverseGeocoderTest.java @@ -0,0 +1,38 @@ +package org.traccar.geocode; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class ReverseGeocoderTest { + + /*@Test + public void testGoogle() { + + ReverseGeocoder reverseGeocoder = new GoogleReverseGeocoder(); + + assertEquals( + "1700 Charleston Rd, Mountain View, CA, US", + reverseGeocoder.getAddress(new AddressFormat(), 37.4217550, -122.0846330)); + } + + @Test + public void testNominatim() { + + ReverseGeocoder reverseGeocoder = new NominatimReverseGeocoder(); + + assertEquals( + "35 West 9th Street, NYC, New York, US", + reverseGeocoder.getAddress(new AddressFormat(), 40.7337807, -73.9974401)); + } + + @Test + public void testGisgraphy() { + + ReverseGeocoder reverseGeocoder = new GisgraphyReverseGeocoder(); + + assertEquals( + "Rue du Jardinet, Paris, FR", + reverseGeocoder.getAddress(new AddressFormat(), 48.8530000, 2.3400000)); + }*/ + +} -- cgit v1.2.3