package com.integralblue.callerid.geocoder; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import com.fasterxml.jackson.annotation.JsonProperty; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import roboguice.util.Ln; import android.location.Address; import com.google.inject.Inject; public class NominatimGeocoder implements Geocoder { protected static class Place { protected static class Address { @JsonProperty("country") private String country; @JsonProperty("country_code") private String countryCode; @JsonProperty("postcode") private String postalCode; public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getCountryCode() { return countryCode; } public void setCountryCode(String countryCode) { this.countryCode = countryCode; } public String getPostalCode() { return postalCode; } public void setPostalCode(String postalCode) { this.postalCode = postalCode; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((country == null) ? 0 : country.hashCode()); result = prime * result + ((countryCode == null) ? 0 : countryCode.hashCode()); result = prime * result + ((postalCode == null) ? 0 : postalCode.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Address other = (Address) obj; if (country == null) { if (other.country != null) return false; } else if (!country.equals(other.country)) return false; if (countryCode == null) { if (other.countryCode != null) return false; } else if (!countryCode.equals(other.countryCode)) return false; if (postalCode == null) { if (other.postalCode != null) return false; } else if (!postalCode.equals(other.postalCode)) return false; return true; } } @JsonProperty("lat") private double latitude; @JsonProperty("lon") private double longitude; @JsonProperty("display_name") private String displayName; @JsonProperty("address") private Address address; public double getLatitude() { return latitude; } public void setLatitude(double latitude) { this.latitude = latitude; } public double getLongitude() { return longitude; } public void setLongitude(double longitude) { this.longitude = longitude; } public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((address == null) ? 0 : address.hashCode()); result = prime * result + ((displayName == null) ? 0 : displayName.hashCode()); long temp; temp = Double.doubleToLongBits(latitude); result = prime * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(longitude); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Place other = (Place) obj; if (address == null) { if (other.address != null) return false; } else if (!address.equals(other.address)) return false; if (displayName == null) { if (other.displayName != null) return false; } else if (!displayName.equals(other.displayName)) return false; if (Double.doubleToLongBits(latitude) != Double .doubleToLongBits(other.latitude)) return false; if (Double.doubleToLongBits(longitude) != Double .doubleToLongBits(other.longitude)) return false; return true; } } @Inject RestTemplate restTemplate; public List<Address> getFromLocation(double latitude, double longitude, int maxResults) throws IOException { return new ArrayList<Address>(); //TODO implement this } public List<Address> getFromLocationName(String locationName, int maxResults) throws IOException { final Map<String,String> urlVariables = new HashMap<String, String>(); urlVariables.put("location", locationName); urlVariables.put("maxResults", Integer.toString(maxResults)); try{ // Nominatim does not handle the HTTP request header "Accept" according to RFC. // If any Accept header other than */* is sent, Nominatim responses with HTTP 406 (Not Acceptable). // So instead of the rather simple line: // final Place[] places = restTemplate.getForObject("http://nominatim.openstreetmap.org/search?q={location}&format=json&addressdetails=1&limit={maxResults}", Place[].class, urlVariables); // we have to manually set the Accept header and make things a bit more complicated. final HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.set("Accept", "*/*"); final HttpEntity<?> requestEntity = new HttpEntity(requestHeaders); final ResponseEntity<Place[]> responseEntity = restTemplate.exchange("http://nominatim.openstreetmap.org/search?q={location}&format=json&addressdetails=1&limit={maxResults}",HttpMethod.GET, requestEntity, Place[].class, urlVariables); final Place[] places = responseEntity.getBody(); return parseResponse(places); }catch(RestClientException e){ Ln.e(e); return new ArrayList<Address>(); } } public List<Address> getFromLocationName(String locationName, int maxResults, double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude, double upperRightLongitude) throws IOException { return new ArrayList<Address>(); //TODO implement this } protected List<Address> parseResponse(final Place[] places) { final List<Address> ret = new ArrayList<Address>(places.length); for(final Place place : places){ final Address address = new Address(Locale.getDefault()); ret.add(address); address.setThoroughfare(place.getDisplayName()); address.setLatitude(place.getLatitude()); address.setLongitude(place.getLongitude()); final Place.Address placeAddress = place.getAddress(); if(placeAddress!=null){ address.setCountryCode(placeAddress.getCountryCode()); address.setCountryName(placeAddress.getCountry()); address.setPostalCode(placeAddress.getPostalCode()); address.setSubAdminArea(placeAddress.getCountry()); } } return ret; } }