aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/geocoder
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/geocoder')
-rw-r--r--src/main/java/org/traccar/geocoder/Address.java110
-rw-r--r--src/main/java/org/traccar/geocoder/AddressFormat.java82
-rw-r--r--src/main/java/org/traccar/geocoder/BanGeocoder.java66
-rw-r--r--src/main/java/org/traccar/geocoder/BingMapsGeocoder.java63
-rw-r--r--src/main/java/org/traccar/geocoder/FactualGeocoder.java58
-rw-r--r--src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java70
-rw-r--r--src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java60
-rw-r--r--src/main/java/org/traccar/geocoder/Geocoder.java30
-rw-r--r--src/main/java/org/traccar/geocoder/GeocoderException.java24
-rw-r--r--src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java55
-rw-r--r--src/main/java/org/traccar/geocoder/GoogleGeocoder.java98
-rw-r--r--src/main/java/org/traccar/geocoder/HereGeocoder.java84
-rw-r--r--src/main/java/org/traccar/geocoder/JsonGeocoder.java121
-rw-r--r--src/main/java/org/traccar/geocoder/MapQuestGeocoder.java63
-rw-r--r--src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java82
-rw-r--r--src/main/java/org/traccar/geocoder/NominatimGeocoder.java91
-rw-r--r--src/main/java/org/traccar/geocoder/OpenCageGeocoder.java76
17 files changed, 1233 insertions, 0 deletions
diff --git a/src/main/java/org/traccar/geocoder/Address.java b/src/main/java/org/traccar/geocoder/Address.java
new file mode 100644
index 000000000..fe39da8e1
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/Address.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+public class Address {
+
+ private String postcode;
+
+ public String getPostcode() {
+ return postcode;
+ }
+
+ public void setPostcode(String postcode) {
+ this.postcode = postcode;
+ }
+
+ private String country;
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ private String state;
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+ private String district;
+
+ public String getDistrict() {
+ return district;
+ }
+
+ public void setDistrict(String district) {
+ this.district = district;
+ }
+
+ private String settlement;
+
+ public String getSettlement() {
+ return settlement;
+ }
+
+ public void setSettlement(String settlement) {
+ this.settlement = settlement;
+ }
+
+ private String suburb;
+
+ public String getSuburb() {
+ return suburb;
+ }
+
+ public void setSuburb(String suburb) {
+ this.suburb = suburb;
+ }
+
+ private String street;
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ private String house;
+
+ public String getHouse() {
+ return house;
+ }
+
+ public void setHouse(String house) {
+ this.house = house;
+ }
+
+ private String formattedAddress;
+
+ public String getFormattedAddress() {
+ return formattedAddress;
+ }
+
+ public void setFormattedAddress(String formattedAddress) {
+ this.formattedAddress = formattedAddress;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/AddressFormat.java b/src/main/java/org/traccar/geocoder/AddressFormat.java
new file mode 100644
index 000000000..ad19432b9
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/AddressFormat.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+
+/**
+ * Available parameters:
+ *
+ * %p - postcode
+ * %c - country
+ * %s - state
+ * %d - district
+ * %t - settlement (town)
+ * %u - suburb
+ * %r - street (road)
+ * %h - house
+ * %f - formatted address
+ *
+ */
+public class AddressFormat extends Format {
+
+ private final String format;
+
+ public AddressFormat() {
+ this("%h %r, %t, %s, %c");
+ }
+
+ public AddressFormat(String format) {
+ this.format = format;
+ }
+
+ private static String replace(String s, String key, String value) {
+ if (value != null) {
+ s = s.replace(key, value);
+ } else {
+ s = s.replaceAll("[, ]*" + key, "");
+ }
+ return s;
+ }
+
+ @Override
+ public StringBuffer format(Object o, StringBuffer stringBuffer, FieldPosition fieldPosition) {
+ Address address = (Address) o;
+ String result = format;
+
+ result = replace(result, "%p", address.getPostcode());
+ result = replace(result, "%c", address.getCountry());
+ result = replace(result, "%s", address.getState());
+ result = replace(result, "%d", address.getDistrict());
+ result = replace(result, "%t", address.getSettlement());
+ result = replace(result, "%u", address.getSuburb());
+ result = replace(result, "%r", address.getStreet());
+ result = replace(result, "%h", address.getHouse());
+ result = replace(result, "%f", address.getFormattedAddress());
+
+ result = result.replaceAll("^[, ]*", "");
+
+ return stringBuffer.append(result);
+ }
+
+ @Override
+ public Address parseObject(String s, ParsePosition parsePosition) {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/BanGeocoder.java b/src/main/java/org/traccar/geocoder/BanGeocoder.java
new file mode 100644
index 000000000..b1f0900a4
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/BanGeocoder.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 Olivier Girondel (olivier@biniou.info)
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+/*
+ * API documentation: https://adresse.data.gouv.fr/api
+ */
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+
+public class BanGeocoder extends JsonGeocoder {
+
+ public BanGeocoder(int cacheSize, AddressFormat addressFormat) {
+ super("https://api-adresse.data.gouv.fr/reverse/?lat=%f&lon=%f", cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ JsonArray result = json.getJsonArray("features");
+
+ if (result != null && !result.isEmpty()) {
+ JsonObject location = result.getJsonObject(0).getJsonObject("properties");
+ Address address = new Address();
+
+ address.setCountry("FR");
+ if (location.containsKey("postcode")) {
+ address.setPostcode(location.getString("postcode"));
+ }
+ if (location.containsKey("context")) {
+ address.setDistrict(location.getString("context"));
+ }
+ if (location.containsKey("name")) {
+ address.setStreet(location.getString("name"));
+ }
+ if (location.containsKey("city")) {
+ address.setSettlement(location.getString("city"));
+ }
+ if (location.containsKey("housenumber")) {
+ address.setHouse(location.getString("housenumber"));
+ }
+ if (location.containsKey("label")) {
+ address.setFormattedAddress(location.getString("label"));
+ }
+
+ return address;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java b/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java
new file mode 100644
index 000000000..32a26ee0c
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/BingMapsGeocoder.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com)
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+
+public class BingMapsGeocoder extends JsonGeocoder {
+
+ public BingMapsGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
+ super(url + "/Locations/%f,%f?key=" + key + "&include=ciso2", cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ JsonArray result = json.getJsonArray("resourceSets");
+ if (result != null) {
+ JsonObject location =
+ result.getJsonObject(0).getJsonArray("resources").getJsonObject(0).getJsonObject("address");
+ if (location != null) {
+ Address address = new Address();
+ if (location.containsKey("addressLine")) {
+ address.setStreet(location.getString("addressLine"));
+ }
+ if (location.containsKey("locality")) {
+ address.setSettlement(location.getString("locality"));
+ }
+ if (location.containsKey("adminDistrict2")) {
+ address.setDistrict(location.getString("adminDistrict2"));
+ }
+ if (location.containsKey("adminDistrict")) {
+ address.setState(location.getString("adminDistrict"));
+ }
+ if (location.containsKey("countryRegionIso2")) {
+ address.setCountry(location.getString("countryRegionIso2").toUpperCase());
+ }
+ if (location.containsKey("postalCode")) {
+ address.setPostcode(location.getString("postalCode"));
+ }
+ if (location.containsKey("formattedAddress")) {
+ address.setFormattedAddress(location.getString("formattedAddress"));
+ }
+ return address;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/FactualGeocoder.java b/src/main/java/org/traccar/geocoder/FactualGeocoder.java
new file mode 100644
index 000000000..c7a68c293
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/FactualGeocoder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com)
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonObject;
+
+public class FactualGeocoder extends JsonGeocoder {
+
+ public FactualGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
+ super(url + "?latitude=%f&longitude=%f&KEY=" + key, cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ JsonObject result = json.getJsonObject("response").getJsonObject("data");
+ if (result != null) {
+ Address address = new Address();
+ if (result.getJsonObject("street_number") != null) {
+ address.setHouse(result.getJsonObject("street_number").getString("name"));
+ }
+ if (result.getJsonObject("street_name") != null) {
+ address.setStreet(result.getJsonObject("street_name").getString("name"));
+ }
+ if (result.getJsonObject("locality") != null) {
+ address.setSettlement(result.getJsonObject("locality").getString("name"));
+ }
+ if (result.getJsonObject("county") != null) {
+ address.setDistrict(result.getJsonObject("county").getString("name"));
+ }
+ if (result.getJsonObject("region") != null) {
+ address.setState(result.getJsonObject("region").getString("name"));
+ }
+ if (result.getJsonObject("country") != null) {
+ address.setCountry(result.getJsonObject("country").getString("name"));
+ }
+ if (result.getJsonObject("postcode") != null) {
+ address.setPostcode(result.getJsonObject("postcode").getString("name"));
+ }
+ return address;
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java b/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java
new file mode 100644
index 000000000..39a3300a0
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/GeocodeFarmGeocoder.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonObject;
+
+public class GeocodeFarmGeocoder extends JsonGeocoder {
+
+ private static String formatUrl(String key, String language) {
+ String url = "https://www.geocode.farm/v3/json/reverse/";
+ url += "?lat=%f&lon=%f&country=us&count=1";
+ if (key != null) {
+ url += "&key=" + key;
+ }
+ if (language != null) {
+ url += "&lang=" + language;
+ }
+ return url;
+ }
+ public GeocodeFarmGeocoder(String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(formatUrl(key, language), cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ Address address = new Address();
+
+ JsonObject result = json
+ .getJsonObject("geocoding_results")
+ .getJsonArray("RESULTS")
+ .getJsonObject(0);
+
+ JsonObject resultAddress = result.getJsonObject("ADDRESS");
+
+ if (result.containsKey("formatted_address")) {
+ address.setFormattedAddress(result.getString("formatted_address"));
+ }
+ if (resultAddress.containsKey("street_number")) {
+ address.setStreet(resultAddress.getString("street_number"));
+ }
+ if (resultAddress.containsKey("street_name")) {
+ address.setStreet(resultAddress.getString("street_name"));
+ }
+ if (resultAddress.containsKey("locality")) {
+ address.setSettlement(resultAddress.getString("locality"));
+ }
+ if (resultAddress.containsKey("admin_1")) {
+ address.setState(resultAddress.getString("admin_1"));
+ }
+ if (resultAddress.containsKey("country")) {
+ address.setCountry(resultAddress.getString("country"));
+ }
+
+ return address;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java b/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java
new file mode 100644
index 000000000..aca360c3d
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/GeocodeXyzGeocoder.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonObject;
+
+public class GeocodeXyzGeocoder extends JsonGeocoder {
+
+ private static String formatUrl(String key) {
+ String url = "https://geocode.xyz/%f,%f?geoit=JSON";
+ if (key != null) {
+ url += "&key=" + key;
+ }
+ return url;
+ }
+
+ public GeocodeXyzGeocoder(String key, int cacheSize, AddressFormat addressFormat) {
+ super(formatUrl(key), cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ Address address = new Address();
+
+ if (json.containsKey("stnumber")) {
+ address.setHouse(json.getString("stnumber"));
+ }
+ if (json.containsKey("staddress")) {
+ address.setStreet(json.getString("staddress"));
+ }
+ if (json.containsKey("city")) {
+ address.setSettlement(json.getString("city"));
+ }
+ if (json.containsKey("region")) {
+ address.setState(json.getString("region"));
+ }
+ if (json.containsKey("prov")) {
+ address.setCountry(json.getString("prov"));
+ }
+ if (json.containsKey("postal")) {
+ address.setPostcode(json.getString("postal"));
+ }
+
+ return address;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/Geocoder.java b/src/main/java/org/traccar/geocoder/Geocoder.java
new file mode 100644
index 000000000..587a27520
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/Geocoder.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+public interface Geocoder {
+
+ interface ReverseGeocoderCallback {
+
+ void onSuccess(String address);
+
+ void onFailure(Throwable e);
+
+ }
+
+ String getAddress(double latitude, double longitude, ReverseGeocoderCallback callback);
+
+}
diff --git a/src/main/java/org/traccar/geocoder/GeocoderException.java b/src/main/java/org/traccar/geocoder/GeocoderException.java
new file mode 100644
index 000000000..608916641
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/GeocoderException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+public class GeocoderException extends RuntimeException {
+
+ public GeocoderException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java
new file mode 100644
index 000000000..3a173f985
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/GisgraphyGeocoder.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonObject;
+
+public class GisgraphyGeocoder extends JsonGeocoder {
+
+ public GisgraphyGeocoder(AddressFormat addressFormat) {
+ this("http://services.gisgraphy.com/reversegeocoding/search", 0, addressFormat);
+ }
+
+ public GisgraphyGeocoder(String url, int cacheSize, AddressFormat addressFormat) {
+ super(url + "?format=json&lat=%f&lng=%f&from=1&to=1", cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ Address address = new Address();
+
+ JsonObject result = json.getJsonArray("result").getJsonObject(0);
+
+ if (result.containsKey("streetName")) {
+ address.setStreet(result.getString("streetName"));
+ }
+ if (result.containsKey("city")) {
+ address.setSettlement(result.getString("city"));
+ }
+ if (result.containsKey("state")) {
+ address.setState(result.getString("state"));
+ }
+ if (result.containsKey("countryCode")) {
+ address.setCountry(result.getString("countryCode"));
+ }
+ if (result.containsKey("formatedFull")) {
+ address.setFormattedAddress(result.getString("formatedFull"));
+ }
+
+ return address;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/GoogleGeocoder.java b/src/main/java/org/traccar/geocoder/GoogleGeocoder.java
new file mode 100644
index 000000000..9494cab45
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/GoogleGeocoder.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonString;
+
+public class GoogleGeocoder extends JsonGeocoder {
+
+ private static String formatUrl(String key, String language) {
+ String url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f";
+ if (key != null) {
+ url += "&key=" + key;
+ }
+ if (language != null) {
+ url += "&language=" + language;
+ }
+ return url;
+ }
+
+ public GoogleGeocoder(String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(formatUrl(key, language), cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ JsonArray results = json.getJsonArray("results");
+
+ if (!results.isEmpty()) {
+ Address address = new Address();
+
+ JsonObject result = (JsonObject) results.get(0);
+ JsonArray components = result.getJsonArray("address_components");
+
+ if (result.containsKey("formatted_address")) {
+ address.setFormattedAddress(result.getString("formatted_address"));
+ }
+
+ for (JsonObject component : components.getValuesAs(JsonObject.class)) {
+
+ String value = component.getString("short_name");
+
+ typesLoop: for (JsonString type : component.getJsonArray("types").getValuesAs(JsonString.class)) {
+
+ switch (type.getString()) {
+ case "street_number":
+ address.setHouse(value);
+ break typesLoop;
+ case "route":
+ address.setStreet(value);
+ break typesLoop;
+ case "locality":
+ address.setSettlement(value);
+ break typesLoop;
+ case "administrative_area_level_2":
+ address.setDistrict(value);
+ break typesLoop;
+ case "administrative_area_level_1":
+ address.setState(value);
+ break typesLoop;
+ case "country":
+ address.setCountry(value);
+ break typesLoop;
+ case "postal_code":
+ address.setPostcode(value);
+ break typesLoop;
+ default:
+ break;
+ }
+ }
+ }
+
+ return address;
+ }
+
+ return null;
+ }
+
+ @Override
+ protected String parseError(JsonObject json) {
+ return json.getString("error_message");
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/HereGeocoder.java b/src/main/java/org/traccar/geocoder/HereGeocoder.java
new file mode 100644
index 000000000..756260b52
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/HereGeocoder.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonObject;
+
+public class HereGeocoder extends JsonGeocoder {
+
+ private static String formatUrl(String id, String key, String language) {
+ String url = "https://reverse.geocoder.api.here.com/6.2/reversegeocode.json";
+ url += "?mode=retrieveAddresses&maxresults=1";
+ url += "&prox=%f,%f,0";
+ url += "&app_id=" + id;
+ url += "&app_code=" + key;
+ if (language != null) {
+ url += "&language=" + language;
+ }
+ return url;
+ }
+
+ public HereGeocoder(String id, String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(formatUrl(id, key, language), cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ JsonObject result = json
+ .getJsonObject("Response")
+ .getJsonArray("View")
+ .getJsonObject(0)
+ .getJsonArray("Result")
+ .getJsonObject(0)
+ .getJsonObject("Location")
+ .getJsonObject("Address");
+
+ if (result != null) {
+ Address address = new Address();
+
+ if (json.containsKey("Label")) {
+ address.setFormattedAddress(json.getString("Label"));
+ }
+
+ if (result.containsKey("HouseNumber")) {
+ address.setHouse(result.getString("HouseNumber"));
+ }
+ if (result.containsKey("Street")) {
+ address.setStreet(result.getString("Street"));
+ }
+ if (result.containsKey("City")) {
+ address.setSettlement(result.getString("City"));
+ }
+ if (result.containsKey("District")) {
+ address.setDistrict(result.getString("District"));
+ }
+ if (result.containsKey("State")) {
+ address.setState(result.getString("State"));
+ }
+ if (result.containsKey("Country")) {
+ address.setCountry(result.getString("Country").toUpperCase());
+ }
+ if (result.containsKey("PostalCode")) {
+ address.setPostcode(result.getString("PostalCode"));
+ }
+
+ return address;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/JsonGeocoder.java b/src/main/java/org/traccar/geocoder/JsonGeocoder.java
new file mode 100644
index 000000000..ed59a1d8d
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/JsonGeocoder.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.Context;
+
+import javax.json.JsonObject;
+import javax.ws.rs.ClientErrorException;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.InvocationCallback;
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public abstract class JsonGeocoder implements Geocoder {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(JsonGeocoder.class);
+
+ private final String url;
+ private final AddressFormat addressFormat;
+
+ private Map<Map.Entry<Double, Double>, String> cache;
+
+ public JsonGeocoder(String url, final int cacheSize, AddressFormat addressFormat) {
+ this.url = url;
+ this.addressFormat = addressFormat;
+ if (cacheSize > 0) {
+ this.cache = Collections.synchronizedMap(new LinkedHashMap<Map.Entry<Double, Double>, String>() {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() > cacheSize;
+ }
+ });
+ }
+ }
+
+ private String handleResponse(
+ double latitude, double longitude, JsonObject json, ReverseGeocoderCallback callback) {
+
+ Address address = parseAddress(json);
+ if (address != null) {
+ String formattedAddress = addressFormat.format(address);
+ if (cache != null) {
+ cache.put(new AbstractMap.SimpleImmutableEntry<>(latitude, longitude), formattedAddress);
+ }
+ if (callback != null) {
+ callback.onSuccess(formattedAddress);
+ }
+ return formattedAddress;
+ } else {
+ String msg = "Empty address. Error: " + parseError(json);
+ if (callback != null) {
+ callback.onFailure(new GeocoderException(msg));
+ } else {
+ LOGGER.warn(msg);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getAddress(
+ final double latitude, final double longitude, final ReverseGeocoderCallback callback) {
+
+ if (cache != null) {
+ String cachedAddress = cache.get(new AbstractMap.SimpleImmutableEntry<>(latitude, longitude));
+ if (cachedAddress != null) {
+ if (callback != null) {
+ callback.onSuccess(cachedAddress);
+ }
+ return cachedAddress;
+ }
+ }
+
+ Invocation.Builder request = Context.getClient().target(String.format(url, latitude, longitude)).request();
+
+ if (callback != null) {
+ request.async().get(new InvocationCallback<JsonObject>() {
+ @Override
+ public void completed(JsonObject json) {
+ handleResponse(latitude, longitude, json, callback);
+ }
+
+ @Override
+ public void failed(Throwable throwable) {
+ callback.onFailure(throwable);
+ }
+ });
+ } else {
+ try {
+ return handleResponse(latitude, longitude, request.get(JsonObject.class), null);
+ } catch (ClientErrorException e) {
+ LOGGER.warn("Geocoder network error", e);
+ }
+ }
+ return null;
+ }
+
+ public abstract Address parseAddress(JsonObject json);
+
+ protected String parseError(JsonObject json) {
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java
new file mode 100644
index 000000000..4029e3f07
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/MapQuestGeocoder.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com)
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+
+public class MapQuestGeocoder extends JsonGeocoder {
+
+ public MapQuestGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
+ super(url + "?key=" + key + "&location=%f,%f", cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ JsonArray result = json.getJsonArray("results");
+ if (result != null) {
+ JsonArray locations = result.getJsonObject(0).getJsonArray("locations");
+ if (locations != null) {
+ JsonObject location = locations.getJsonObject(0);
+
+ Address address = new Address();
+
+ if (location.containsKey("street")) {
+ address.setStreet(location.getString("street"));
+ }
+ if (location.containsKey("adminArea5")) {
+ address.setSettlement(location.getString("adminArea5"));
+ }
+ if (location.containsKey("adminArea4")) {
+ address.setDistrict(location.getString("adminArea4"));
+ }
+ if (location.containsKey("adminArea3")) {
+ address.setState(location.getString("adminArea3"));
+ }
+ if (location.containsKey("adminArea1")) {
+ address.setCountry(location.getString("adminArea1").toUpperCase());
+ }
+ if (location.containsKey("postalCode")) {
+ address.setPostcode(location.getString("postalCode"));
+ }
+
+ return address;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java b/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java
new file mode 100644
index 000000000..2b70708a1
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/MapmyIndiaGeocoder.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+
+public class MapmyIndiaGeocoder extends JsonGeocoder {
+
+ public MapmyIndiaGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
+ super(url + "/" + key + "/rev_geocode?lat=%f&lng=%f", cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ JsonArray results = json.getJsonArray("results");
+
+ if (!results.isEmpty()) {
+ Address address = new Address();
+
+ JsonObject result = (JsonObject) results.get(0);
+
+ if (result.containsKey("formatted_address")) {
+ address.setFormattedAddress(result.getString("formatted_address"));
+ }
+
+ if (result.containsKey("house_number") && !result.getString("house_number").isEmpty()) {
+ address.setHouse(result.getString("house_number"));
+ } else if (result.containsKey("house_name") && !result.getString("house_name").isEmpty()) {
+ address.setHouse(result.getString("house_name"));
+ }
+
+ if (result.containsKey("street")) {
+ address.setStreet(result.getString("street"));
+ }
+
+ if (result.containsKey("locality") && !result.getString("locality").isEmpty()) {
+ address.setSuburb(result.getString("locality"));
+ } else if (result.containsKey("sublocality") && !result.getString("sublocality").isEmpty()) {
+ address.setSuburb(result.getString("sublocality"));
+ } else if (result.containsKey("subsublocality") && !result.getString("subsublocality").isEmpty()) {
+ address.setSuburb(result.getString("subsublocality"));
+ }
+
+ if (result.containsKey("city") && !result.getString("city").isEmpty()) {
+ address.setSettlement(result.getString("city"));
+ } else if (result.containsKey("village") && !result.getString("village").isEmpty()) {
+ address.setSettlement(result.getString("village"));
+ }
+
+ if (result.containsKey("district")) {
+ address.setDistrict(result.getString("district"));
+ } else if (result.containsKey("subDistrict")) {
+ address.setDistrict(result.getString("subDistrict"));
+ }
+
+ if (result.containsKey("state")) {
+ address.setState(result.getString("state"));
+ }
+
+ if (result.containsKey("pincode")) {
+ address.setPostcode(result.getString("pincode"));
+ }
+
+ return address;
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/org/traccar/geocoder/NominatimGeocoder.java b/src/main/java/org/traccar/geocoder/NominatimGeocoder.java
new file mode 100644
index 000000000..8db25bf15
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/NominatimGeocoder.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2014 - 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonObject;
+
+public class NominatimGeocoder extends JsonGeocoder {
+
+ private static String formatUrl(String url, String key, String language) {
+ if (url == null) {
+ url = "https://nominatim.openstreetmap.org/reverse";
+ }
+ url += "?format=json&lat=%f&lon=%f&zoom=18&addressdetails=1";
+ if (key != null) {
+ url += "&key=" + key;
+ }
+ if (language != null) {
+ url += "&accept-language=" + language;
+ }
+ return url;
+ }
+
+ public NominatimGeocoder(String url, String key, String language, int cacheSize, AddressFormat addressFormat) {
+ super(formatUrl(url, key, language), cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ JsonObject result = json.getJsonObject("address");
+
+ if (result != null) {
+ Address address = new Address();
+
+ if (json.containsKey("display_name")) {
+ address.setFormattedAddress(json.getString("display_name"));
+ }
+
+ if (result.containsKey("house_number")) {
+ address.setHouse(result.getString("house_number"));
+ }
+ if (result.containsKey("road")) {
+ address.setStreet(result.getString("road"));
+ }
+ if (result.containsKey("suburb")) {
+ address.setSuburb(result.getString("suburb"));
+ }
+
+ if (result.containsKey("village")) {
+ address.setSettlement(result.getString("village"));
+ } else if (result.containsKey("town")) {
+ address.setSettlement(result.getString("town"));
+ } else if (result.containsKey("city")) {
+ address.setSettlement(result.getString("city"));
+ }
+
+ if (result.containsKey("state_district")) {
+ address.setDistrict(result.getString("state_district"));
+ } else if (result.containsKey("region")) {
+ address.setDistrict(result.getString("region"));
+ }
+
+ if (result.containsKey("state")) {
+ address.setState(result.getString("state"));
+ }
+ if (result.containsKey("country_code")) {
+ address.setCountry(result.getString("country_code").toUpperCase());
+ }
+ if (result.containsKey("postcode")) {
+ address.setPostcode(result.getString("postcode"));
+ }
+
+ return address;
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java
new file mode 100644
index 000000000..822b6e91e
--- /dev/null
+++ b/src/main/java/org/traccar/geocoder/OpenCageGeocoder.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014 - 2015 Stefaan Van Dooren (stefaan.vandooren@gmail.com)
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.geocoder;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+
+public class OpenCageGeocoder extends JsonGeocoder {
+
+ public OpenCageGeocoder(String url, String key, int cacheSize, AddressFormat addressFormat) {
+ super(url + "/json?q=%f,%f&no_annotations=1&key=" + key, cacheSize, addressFormat);
+ }
+
+ @Override
+ public Address parseAddress(JsonObject json) {
+ JsonArray result = json.getJsonArray("results");
+ if (result != null) {
+ JsonObject location = result.getJsonObject(0).getJsonObject("components");
+ if (location != null) {
+ Address address = new Address();
+
+ if (result.getJsonObject(0).containsKey("formatted")) {
+ address.setFormattedAddress(result.getJsonObject(0).getString("formatted"));
+ }
+ if (location.containsKey("building")) {
+ address.setHouse(location.getString("building"));
+ }
+ if (location.containsKey("house_number")) {
+ address.setHouse(location.getString("house_number"));
+ }
+ if (location.containsKey("road")) {
+ address.setStreet(location.getString("road"));
+ }
+ if (location.containsKey("suburb")) {
+ address.setSuburb(location.getString("suburb"));
+ }
+ if (location.containsKey("city")) {
+ address.setSettlement(location.getString("city"));
+ }
+ if (location.containsKey("city_district")) {
+ address.setSettlement(location.getString("city_district"));
+ }
+ if (location.containsKey("county")) {
+ address.setDistrict(location.getString("county"));
+ }
+ if (location.containsKey("state")) {
+ address.setState(location.getString("state"));
+ }
+ if (location.containsKey("country_code")) {
+ address.setCountry(location.getString("country_code").toUpperCase());
+ }
+ if (location.containsKey("postcode")) {
+ address.setPostcode(location.getString("postcode"));
+ }
+
+ return address;
+ }
+ }
+ return null;
+ }
+
+}