package com.dougkeen.bart.networktasks; import java.io.IOException; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.util.List; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import android.os.AsyncTask; import android.util.Log; import android.util.Xml; import com.dougkeen.bart.model.Constants; import com.dougkeen.bart.model.RealTimeDepartures; import com.dougkeen.bart.model.Route; import com.dougkeen.bart.model.StationPair; public abstract class GetRealTimeDeparturesTask extends AsyncTask { private final static String ETD_URL = "http://api.bart.gov/api/etd.aspx?cmd=etd&key=" + Constants.API_KEY + "&orig=%1$s&dir=%2$s"; private final static String ETD_URL_NO_DIRECTION = "http://api.bart.gov/api/etd.aspx?cmd=etd&key=" + Constants.API_KEY + "&orig=%1$s"; private final static int MAX_ATTEMPTS = 5; private Exception mException; private List mRoutes; private final boolean ignoreDirection; public GetRealTimeDeparturesTask(boolean ignoreDirection) { super(); this.ignoreDirection = ignoreDirection; } @Override protected RealTimeDepartures doInBackground(StationPair... paramsArray) { // Always expect one param StationPair params = paramsArray[0]; mRoutes = params.getOrigin().getDirectRoutesForDestination( params.getDestination()); boolean hasDirectLine = false; for (Route route : mRoutes) { if (!route.hasTransfer()) { hasDirectLine = true; break; } } if (mRoutes.isEmpty() || (params.getOrigin().transferFriendly && !hasDirectLine)) { mRoutes.addAll(params.getOrigin().getTransferRoutes( params.getDestination())); } if (!isCancelled()) { return getDeparturesFromNetwork(params, 0); } else { return null; } } private RealTimeDepartures getDeparturesFromNetwork(StationPair params, int attemptNumber) { String xml = null; try { String url; if (ignoreDirection || params.getOrigin().endOfLine) { url = String.format(ETD_URL_NO_DIRECTION, params.getOrigin().abbreviation); } else { url = String.format(ETD_URL, params.getOrigin().abbreviation, mRoutes.get(0).getDirection()); } HttpUriRequest request = new HttpGet(url); EtdContentHandler handler = new EtdContentHandler( params.getOrigin(), params.getDestination(), mRoutes); if (isCancelled()) { return null; } HttpResponse response = NetworkUtils.executeWithRecovery(request); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new IOException("Server returned " + response.getStatusLine().toString()); } StringWriter writer = new StringWriter(); IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8"); xml = writer.toString(); if (xml.length() == 0) { throw new IOException("Server returned blank xml document"); } try { Xml.parse(xml, handler); } catch (Exception e) { mException = new IOException("Server returned malformed xml: " + xml); return null; } final RealTimeDepartures realTimeDepartures = handler .getRealTimeDepartures(); return realTimeDepartures; } catch (MalformedURLException e) { throw new RuntimeException(e); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } catch (IOException e) { if (attemptNumber < MAX_ATTEMPTS - 1) { try { Log.w(Constants.TAG, "Attempt to contact server failed... retrying in 3s", e); Thread.sleep(3000); } catch (InterruptedException interrupt) { // Ignore... just go on to next attempt } return getDeparturesFromNetwork(params, attemptNumber + 1); } else { mException = new Exception("Could not contact BART system", e); return null; } } } @Override protected void onPostExecute(RealTimeDepartures result) { if (result != null) { onResult(result); } else { onError(mException); } } public abstract void onResult(RealTimeDepartures result); public abstract void onError(Exception exception); }