package org.commcare.android.tasks;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.commcare.android.tasks.templates.CommCareTask;
import org.commcare.android.util.SessionUnavailableException;
import org.commcare.util.CommCarePlatform;
import org.javarosa.core.services.Logger;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
/**
* Runs various tasks that diagnose problems that a user may be facing in connecting to commcare services.
* @author srengesh
*/
//CommCareTask<A, B, C, R>
public abstract class ConnectionDiagnosticTask<R> extends CommCareTask<Void, String, ConnectionDiagnosticTask.Test, R>
{
Context c;
CommCarePlatform platform;
public static enum Test
{
isOnline,
googlePing,
commCarePing
}
public static final int CONNECTION_ID = 12335800;
/** Problem reported via connection diagnostic tool **/
public static final String CONNECTION_DIAGNOSTIC_REPORT = "connection-report";
//strings used to in various diagnostics tests. Change these values if the URLs/HTML code is changed.
private static final String googleURL = "www.google.com";
private static final String commcareURL = "http://www.commcarehq.org/serverup.txt";
private static final String commcareHTML = "success";
private static final String pingPrefix = "ping -c 1 ";
//the various log messages that will be returned regarding the outcomes of the tests
private static final String logNotConnectedMessage = "Network test: Not connected.";
private static final String logConnectionSuccessMessage = "Network test: Success.";
private static final String logGoogleNullPointerMessage = "Google ping test: Process could not be started.";
private static final String logGoogleIOErrorMessage = "Google ping test: Local error.";
private static final String logGoogleInterruptedMessage = "Google ping test: Process was interrupted.";
private static final String logGoogleSuccessMessage = "Google ping test: Success.";
private static final String logGoogleUnexpectedResultMessage = "Google ping test: Unexpected HTML Result.";
private static final String logCCIllegalStateMessage = "CCHQ ping test: Illegal state.";
private static final String logCCNetworkFailureMessge = "CCHQ ping test: Network failure.";
private static final String logCCIOErrorMessage = "CCHQ ping test: Local error.";
private static final String logCCUnexpectedResultMessage = "CCHQ ping test: Unexpected HTML result";
private static final String logCCSuccessMessage = "CCHQ ping test: Success.";
public ConnectionDiagnosticTask(Context c, CommCarePlatform platform) throws SessionUnavailableException
{
this.c = c;
this.platform = platform;
this.taskId = CONNECTION_ID;
}
//onProgressUpdate(<B>)
//onPostExecute(<C>)
//onCancelled()
/*
* (non-Javadoc)
* @see org.commcare.android.tasks.templates.CommCareTask#doTaskBackground(java.lang.Object[])
*
* doTaskBackground(<A>) returns <C>
*/
@Override
protected Test doTaskBackground(Void... params)
{
Test out = null;
if(!isOnline(this.c))
{
out = Test.isOnline;
}
else if(!pingSuccess(googleURL))
{
out = Test.googlePing;
}
else if(!pingCC(commcareURL))
{
out = Test.commCarePing;
}
return out;
}
//checks if the network is connected or not.
private boolean isOnline(Context context)
{
ConnectivityManager conManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = conManager.getActiveNetworkInfo();
boolean notInAirplaneMode = (netInfo != null && netInfo.isConnected());
//if user is not online, log not connected. if online, log success
String logMessage = !notInAirplaneMode? logNotConnectedMessage : logConnectionSuccessMessage;
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logMessage);
if(notInAirplaneMode)
{
return true;
}
return false;
}
//check if a ping to a specific ip address (used for google url) is successful.
private boolean pingSuccess(String url)
{
Process pingCommand = null;
try {
//append the input url to the ping command
StringBuilder pingURLBuilder = new StringBuilder(pingPrefix);
pingURLBuilder.append(url);
String pingURL = pingURLBuilder.toString();
//run the ping command at runtime
pingCommand = java.lang.Runtime.getRuntime().exec(pingURL);
if(pingCommand == null)
{
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logGoogleNullPointerMessage);
return false;
}
}
catch (IOException e)
{
StringBuilder out = new StringBuilder(logGoogleIOErrorMessage);
out.append(System.getProperty("line.separator"));
out.append("Stack trace: ");
out.append(ExceptionReportTask.getStackTrace(e));
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, out.toString());
return false;
}
int pingReturn = Integer.MAX_VALUE;
try
{
pingReturn = pingCommand.waitFor();
}
catch (InterruptedException e)
{
StringBuilder out = new StringBuilder(logGoogleInterruptedMessage);
out.append(System.getProperty("line.separator"));
out.append("Stack trace: ");
out.append(ExceptionReportTask.getStackTrace(e));
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, out.toString());
return false;
}
//0 if success, 2 if fail
String messageOut = pingReturn==0? logGoogleSuccessMessage : logGoogleUnexpectedResultMessage;
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, messageOut);
if(pingReturn != 0)
{
return false;
}
return true;
}
private boolean pingCC(String url)
{
//uses HttpClient and HttpGet to read the HTML from the specified url
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
InputStream stream = null;
String htmlLine = null;
BufferedReader buffer = null;
InputStreamReader reader = null;
try {
//read html using an input stream reader
stream = client.execute(get).getEntity().getContent();
reader = new InputStreamReader(stream);
buffer = new BufferedReader(reader);
//should read "success" if the server is up.
htmlLine = buffer.readLine();
} catch (IllegalStateException e) {
//if a stream to this web address has already been invoked on the same thread
StringBuilder out = new StringBuilder(logCCIllegalStateMessage);
out.append(System.getProperty("line.separator"));
out.append("Stack trace: ");
out.append(ExceptionReportTask.getStackTrace(e));
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, out.toString());
return false;
} catch (ClientProtocolException e) {
//general HTTP Exception
StringBuilder out = new StringBuilder(logCCNetworkFailureMessge);
out.append(System.getProperty("line.separator"));
out.append("Stack trace: ");
out.append(ExceptionReportTask.getStackTrace(e));
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, out.toString());
return false;
} catch (IOException e) {
//error on client side
StringBuilder out = new StringBuilder(logCCIOErrorMessage);
out.append(System.getProperty("line.separator"));
out.append("Stack trace: ");
out.append(ExceptionReportTask.getStackTrace(e));
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, out.toString());
return false;
} finally {
if(buffer != null)
{
try {
buffer.close();
} catch (IOException e) {
StringBuilder out = new StringBuilder(logCCIOErrorMessage);
out.append(System.getProperty("line.separator"));
out.append("Stack trace: ");
out.append(ExceptionReportTask.getStackTrace(e));
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, out.toString());
return false;
}
}
if(reader != null)
{
try {
reader.close();
} catch (IOException e) {
StringBuilder out = new StringBuilder(logCCIOErrorMessage);
out.append(System.getProperty("line.separator"));
out.append("Stack trace: ");
out.append(ExceptionReportTask.getStackTrace(e));
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, out.toString());
return false;
}
}
if(stream != null)
{
try {
stream.close();
} catch (IOException e) {
StringBuilder out = new StringBuilder(logCCIOErrorMessage);
out.append(System.getProperty("line.separator"));
out.append("Stack trace: ");
out.append(ExceptionReportTask.getStackTrace(e));
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, out.toString());
return false;
}
}
}
if(htmlLine.equals(commcareHTML))
{
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logCCSuccessMessage);
return true;
}
else
{
Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logCCUnexpectedResultMessage);
return false;
}
}
}