Before Google provided HTTP reverse-geocoding service, the world was a dark place if you needed reverse-geocoding in your application.
The only way to perform reverse-geocoding was using javascript API that too using third party library.
Since the application I was working on a year or so back required reverse-geocoding- worse it was central to our geo-location based reporting – I had to find a
way of reverse geocoding high volume longitude/latitude pairs on the server side.
After contemplating various solutions/non-solutions I decided to give myself some time to come up with a solution that didn’t
require us to pay for premium service or ditch googlemaps altogether.
That’s when I came across HtmlUnit. As soon as I read about its capabilities, I suddenly had a brilliant idea!
The idea was to use HtmlUnit to access a page with a small googlemap loaded ( reverse geocoding using GDirection required an instance of googlemap to be present)
on it, that has a form for entering longitude and latitude, a button to submit reverse-geocoding request and a DIV element for populating reverse-geocoded address response
from Google.
Javascript code:
// GMap2 object
var map;
// GReverseGeocoder object
var rg;
// text input fields
var lat;
var lng;
// result div
var addressText;
function load() {
if (GBrowserIsCompatible()) {
lat = document.getElementById("lat");
lng = document.getElementById("lng");
addressText = document.getElementById("address");
map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(-33.83955, 151.2084), 15);
map.addControl(new GLargeMapControl());
rg = new GReverseGeocoder(map);
// add listner for the result
GEvent.addListener(rg, "load", function(response){
addressText.innerHTML=response.address
});
//add listener for error response
GEvent.addListener(rg, "error", function(lastpoint){
addressText.innerHTML = "ERROR:point " + lastpoint;
});
// Listener to detect clicks on map to get coordinates to fill in the lat and lng fields-for testing purpose.
GEvent.addListener(map, "click", function(marker, point){
lat.value=point.lat();
lng.value=point.lng();
});
}
}
// get the input form lat and lng fields and issue a reverse geocode
// request
function reverse(){
var point = new GLatLng(lat.value,lng.value);
rg.reverseGeocode(point);
return false;
}
HTML code:
<form name="rev" id="rev" action="" method="post" onSubmit=" reverse();return false;">
<table>
<tr><td>Latitude (WGS84)</td><td><input id="lat" name="lat" type="text" size="20" value='' /></td></tr>
<tr><td>Longitude (WGS84)</td><td><input id="lng" name="lng" type="text" size="20" value='' /></td></tr>
<tr><td><input name="submit" id="submit" type="submit" onClick="reverse()" value="Get Address"></td><td> address:<div id="address"></div></td></tr>
<tr><td colspan="2"><div id="map" style="width:400px; height:400px;"></div></td></tr>
</table>
</form>
I wrote a Java method which accessed the webpage, populated longitude/latitude textbox in the webpage, clicked the submit button, and wait for the response
to be populated in the div element -all done using HtmlUnit’s headless browser. After sleeping for 2 seconds the method then read the content of the address div element.
And it worked flawlessly.
Java Code:
public static String latLngToAddress(Float lat, Float lon) {
try {
WebClient wc = new WebClient();
wc.setThrowExceptionOnScriptError(false);
HtmlPage page = (HtmlPage) wc.getPage("http://localhost:8084/ReverseGeocoder/");
HtmlForm form = page.getFormByName("rev");
HtmlInput latInput = (HtmlTextInput) form.getInputByName("lat");
latInput .setValueAttribute(lat.toString());
HtmlTextInput lngInput = (HtmlTextInput) form.getInputByName("lng");
lngInput.setValueAttribute(lon.toString());
HtmlSubmitInput button = (HtmlSubmitInput) form.getInputByName("submit");
button.click();
Thread.sleep(2000);
return page.getElementById("address").getTextContent();
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
I spent quite a bit of time then to finally come up with this solution. But before I finished the application, Google finally provided HTTP reverse-geocoding service which meant that there was
no need to use my solution. But at least I’m glad I tried it and came up with a solution when none existed
