package com.ta.util.http;
import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.protocol.HttpContext;
public class AsyncHttpRequest implements Runnable
{
private final AbstractHttpClient client;
private final HttpContext context;
private final HttpUriRequest request;
private final AsyncHttpResponseHandler responseHandler;
private boolean isBinaryRequest;
private int executionCount;
public AsyncHttpRequest(AbstractHttpClient client, HttpContext context,
HttpUriRequest request, AsyncHttpResponseHandler responseHandler)
{
this.client = client;
this.context = context;
this.request = request;
this.responseHandler = responseHandler;
if (responseHandler instanceof BinaryHttpResponseHandler)
{
this.isBinaryRequest = true;
} else if (responseHandler instanceof FileHttpResponseHandler)
{
FileHttpResponseHandler fileHttpResponseHandler = (FileHttpResponseHandler) responseHandler;
File tempFile = fileHttpResponseHandler.getTempFile();
if (tempFile.exists())
{
long previousFileSize = tempFile.length();
fileHttpResponseHandler.setPreviousFileSize(previousFileSize);
this.request.setHeader("RANGE", "bytes=" + previousFileSize
+ "-");
}
}
}
@Override
public void run()
{
try
{
if (responseHandler != null)
{
responseHandler.sendStartMessage();
}
makeRequestWithRetries();
if (responseHandler != null)
{
responseHandler.sendFinishMessage();
}
} catch (IOException e)
{
if (responseHandler != null)
{
responseHandler.sendFinishMessage();
if (this.isBinaryRequest)
{
responseHandler.sendFailureMessage(e, (byte[]) null);
} else
{
responseHandler.sendFailureMessage(e, (String) null);
}
}
}
}
private void makeRequest() throws IOException
{
if (!Thread.currentThread().isInterrupted())
{
try
{
HttpResponse response = client.execute(request, context);
if (!Thread.currentThread().isInterrupted())
{
if (responseHandler != null)
{
responseHandler.sendResponseMessage(response);
}
} else
{
// TODO: should raise InterruptedException? this block is
// reached whenever the request is cancelled before its
// response is received
}
} catch (IOException e)
{
if (!Thread.currentThread().isInterrupted())
{
throw e;
}
}
}
}
private void makeRequestWithRetries() throws ConnectException
{
// This is an additional layer of retry logic lifted from droid-fu
// See:
// https://github.com/kaeppler/droid-fu/blob/master/src/main/java/com/github/droidfu/http/BetterHttpRequestBase.java
boolean retry = true;
IOException cause = null;
HttpRequestRetryHandler retryHandler = client
.getHttpRequestRetryHandler();
while (retry)
{
try
{
makeRequest();
return;
} catch (UnknownHostException e)
{
if (responseHandler != null)
{
responseHandler.sendFailureMessage(e, "can't resolve host");
}
return;
} catch (SocketException e)
{
// Added to detect host unreachable
if (responseHandler != null)
{
responseHandler.sendFailureMessage(e, "can't resolve host");
}
return;
} catch (SocketTimeoutException e)
{
if (responseHandler != null)
{
responseHandler.sendFailureMessage(e, "socket time out");
}
return;
} catch (IOException e)
{
cause = e;
retry = retryHandler.retryRequest(cause, ++executionCount,
context);
} catch (NullPointerException e)
{
// there's a bug in HttpClient 4.0.x that on some occasions
// causes
// DefaultRequestExecutor to throw an NPE, see
// http://code.google.com/p/android/issues/detail?id=5255
cause = new IOException("NPE in HttpClient" + e.getMessage());
retry = retryHandler.retryRequest(cause, ++executionCount,
context);
}
}
// no retries left, crap out with exception
ConnectException ex = new ConnectException();
ex.initCause(cause);
throw ex;
}
}