package org.androad.sys.ors.lus.openrouteservice; import java.io.BufferedInputStream; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.SocketException; import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.osmdroid.util.GeoPoint; import org.androad.sys.ors.adt.Error; import org.androad.sys.ors.adt.GeocodedAddress; import org.androad.sys.ors.adt.lus.Country; import org.androad.sys.ors.adt.lus.ICountrySubdivision; import org.androad.sys.ors.adt.lus.ReverseGeocodePreferenceType; import org.androad.sys.ors.exceptions.ORSException; import org.androad.sys.ors.lus.LUSRequester; import org.androad.util.constants.Constants; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import android.content.Context; import android.util.Log; public class OpenRouteServiceLUSRequester implements Constants, LUSRequester { // =========================================================== // Constants // =========================================================== private static final boolean WORKAROUND_STRUCTURED_AS_FREEFORM = true; // =========================================================== // Fields // =========================================================== private String url_locationutilityservice; // =========================================================== // Constructors // =========================================================== public OpenRouteServiceLUSRequester(final String url) { this.url_locationutilityservice = url; } // =========================================================== // Getter & Setter // =========================================================== public ArrayList<GeocodedAddress> requestReverseGeocode(final Context ctx, final GeoPoint aGeoPoint, final ReverseGeocodePreferenceType aPreferenceType) throws MalformedURLException, IOException, SAXException, ORSException{ if(Math.abs(aGeoPoint.getLatitudeE6()) < 10000 && Math.abs(aGeoPoint.getLongitudeE6()) < 10000) { return null; } return request(ctx, OpenRouteServiceLUSRequestComposer.reverseGeocode(ctx, aGeoPoint, aPreferenceType), true); } public ArrayList<GeocodedAddress> requestFreeformAddress(final Context ctx, final Country nat, final String freeFormAddress) throws MalformedURLException, IOException, SAXException, ORSException{ return request(ctx, OpenRouteServiceLUSRequestComposer.createFreeformAddressRequest(ctx, nat, freeFormAddress), false); } public ArrayList<GeocodedAddress> requestStreetaddressCity(final Context ctx, final Country nat, final ICountrySubdivision pCountrySubdivision, final String pCity, final String pStreetName, final String pStreetNumber) throws MalformedURLException, IOException, SAXException, ORSException{ if(shouldDoWorkaround(nat)) { return request(ctx, OpenRouteServiceLUSRequestComposer.createFreeformAddressRequest(ctx, nat, structuredToFreeform(pCountrySubdivision, pCity, pStreetName, pStreetNumber)), false); } else { return request(ctx, OpenRouteServiceLUSRequestComposer.createStreetaddressCityRequest(ctx, nat, pCountrySubdivision, pCity, pStreetName, pStreetNumber), false); } } public ArrayList<GeocodedAddress> requestStreetaddressPostalcode(final Context ctx, final Country nat, final ICountrySubdivision pCountrySubdivision, final String pPostalCode, final String pStreetName, final String pStreetNumber) throws MalformedURLException, IOException, SAXException, ORSException{ if(shouldDoWorkaround(nat)) { return request(ctx, OpenRouteServiceLUSRequestComposer.createFreeformAddressRequest(ctx, nat, structuredToFreeform(pCountrySubdivision, pPostalCode, pStreetName, pStreetNumber)), false); } else { return request(ctx, OpenRouteServiceLUSRequestComposer.createStreetaddressPostalcodeRequest(ctx, nat, pCountrySubdivision, pPostalCode, pStreetName, pStreetNumber), false); } } private boolean shouldDoWorkaround(final Country nat) { final boolean doWorkaround; switch(nat){ case USA: case CANADA: doWorkaround = false; break; default: doWorkaround = WORKAROUND_STRUCTURED_AS_FREEFORM; // true } return doWorkaround; } // =========================================================== // Methods from SuperClass/Interfaces // =========================================================== // =========================================================== // Methods // =========================================================== private String structuredToFreeform(final ICountrySubdivision pCountrySubdivision, final String pCityOrZipCode, final String pStreetName, final String pStreetNumber) throws ORSException { /* Either one of these has to be set. */ if((pCityOrZipCode == null || pCityOrZipCode.length() == 0) && (pStreetName == null || pStreetName.length() == 0)) { throw new ORSException(new Error(Error.ERRORCODE_UNKNOWN, Error.SEVERITY_ERROR, "org.androad.ors.lus.structuredToFreeform.LUSRequester.structuredToFreeform()", "Either street/zip or streetname has to be set.")); } final StringBuilder sb = new StringBuilder(); if(pCityOrZipCode != null){ sb.append(pCityOrZipCode); if(pStreetName != null){ sb.append(','); } } if(pStreetName != null){ sb.append(pStreetName); if(pStreetNumber != null){ sb.append(' ') .append(pStreetNumber); } } return sb.toString(); } private ArrayList<GeocodedAddress> request(final Context ctx, final String locationRequest, final boolean pIsReverseGeocode) throws SAXException, ORSException, IOException{ final URL requestURL = new URL(url_locationutilityservice); final HttpURLConnection acon = (HttpURLConnection) requestURL.openConnection(); acon.setAllowUserInteraction(false); acon.setRequestMethod("POST"); acon.setRequestProperty("Content-Type", "application/xml"); acon.setDoOutput(true); acon.setDoInput(true); acon.setUseCaches(false); final BufferedWriter xmlOut; try{ xmlOut = new BufferedWriter(new OutputStreamWriter(acon.getOutputStream())); }catch(final SocketException se){ throw new ORSException(new Error(Error.ERRORCODE_UNKNOWN, Error.SEVERITY_ERROR, "org.androad.ors.lus.LUSRequester.request(...)", "Host unreachable.")); }catch(final UnknownHostException uhe){ throw new ORSException(new Error(Error.ERRORCODE_UNKNOWN, Error.SEVERITY_ERROR, "org.androad.ors.lus.LUSRequester.request(...)", "Host unresolved.")); } // Log.d(DEBUGTAG, locationRequest); xmlOut.write(locationRequest); xmlOut.flush(); xmlOut.close(); /* Get a SAXParser from the SAXPArserFactory. */ final SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp; try { sp = spf.newSAXParser(); } catch (final ParserConfigurationException e) { throw new SAXException(e); } /* Get the XMLReader of the SAXParser we created. */ final XMLReader xr = sp.getXMLReader(); /* Create a new ContentHandler and apply it to the XML-Reader*/ final DefaultHandler openLUSParser = (pIsReverseGeocode) ? new OpenRouteServiceLUSReverseGeocodeParser() : new OpenRouteServiceLUSGeocodeParser(); xr.setContentHandler(openLUSParser); /* Parse the xml-data from our URL. */ try{ xr.parse(new InputSource(new BufferedInputStream(acon.getInputStream()))); }catch(final Exception e){ Log.e(DEBUGTAG, "Error", e); } /* The Handler now provides the parsed data to us. */ if(pIsReverseGeocode) { return ((OpenRouteServiceLUSReverseGeocodeParser)openLUSParser).getAddresses(); } else { return ((OpenRouteServiceLUSGeocodeParser)openLUSParser).getAddresses(); } } // =========================================================== // Inner and Anonymous Classes // =========================================================== }