From a793a5f2e39b4e5cd6840e912997449a618846f6 Mon Sep 17 00:00:00 2001 From: Jesse Young Date: Mon, 19 Sep 2011 17:18:56 -0700 Subject: [PATCH] use http connection pooling to improve performance (especially over ssl) --- src/org/envaya/kalsms/App.java | 55 +++++++++++++++++++++-- src/org/envaya/kalsms/task/HttpTask.java | 56 +++++++++++------------- 2 files changed, 76 insertions(+), 35 deletions(-) diff --git a/src/org/envaya/kalsms/App.java b/src/org/envaya/kalsms/App.java index dbdebd8..aadd38b 100755 --- a/src/org/envaya/kalsms/App.java +++ b/src/org/envaya/kalsms/App.java @@ -18,12 +18,23 @@ import android.text.SpannableStringBuilder; import android.util.Log; import java.text.DateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.http.client.HttpClient; +import org.apache.http.conn.params.ConnManagerParams; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.message.BasicNameValuePair; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; import org.envaya.kalsms.receiver.OutgoingMessagePoller; import org.envaya.kalsms.task.HttpTask; import org.envaya.kalsms.task.PollerTask; @@ -83,13 +94,19 @@ public final class App extends Application { private SharedPreferences settings; private MmsObserver mmsObserver; private SpannableStringBuilder displayedLog = new SpannableStringBuilder(); - private long lastLogTime; + private long lastLogTime; + // list of package names (e.g. org.envaya.kalsms, or org.envaya.kalsms.packXX) + // for this package and all expansion packs private List outgoingMessagePackages = new ArrayList(); + + // count to provide round-robin selection of expansion packs private int outgoingMessageCount = -1; + + // map of package name => sorted list of timestamps of outgoing messages private HashMap> outgoingTimestamps = new HashMap>(); - + private MmsUtils mmsUtils; @Override @@ -147,6 +164,7 @@ public final class App extends Application { } ArrayList sent = outgoingTimestamps.get(packageName); + Long ct = System.currentTimeMillis(); //log(packageName + " SMS send size=" + sent.size()); @@ -599,5 +617,34 @@ public final class App extends Application { } } return false; - } + } + + private HttpClient httpClient; + + public synchronized HttpClient getHttpClient() + { + if (httpClient == null) + { + // via http://thinkandroid.wordpress.com/2009/12/31/creating-an-http-client-example/ + // also http://hc.apache.org/httpclient-3.x/threading.html + + HttpParams httpParams = new BasicHttpParams(); + HttpConnectionParams.setConnectionTimeout(httpParams, 8000); + HttpConnectionParams.setSoTimeout(httpParams, 8000); + HttpProtocolParams.setContentCharset(httpParams, "utf-8"); + + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + + final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory(); + sslSocketFactory.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); + + registry.register(new Scheme("https", sslSocketFactory, 443)); + + ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(httpParams, registry); + + httpClient = new DefaultHttpClient(manager, httpParams); + } + return httpClient; + } } diff --git a/src/org/envaya/kalsms/task/HttpTask.java b/src/org/envaya/kalsms/task/HttpTask.java index eaf7e6a..3678a4c 100755 --- a/src/org/envaya/kalsms/task/HttpTask.java +++ b/src/org/envaya/kalsms/task/HttpTask.java @@ -14,9 +14,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -25,15 +23,10 @@ import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.FormBodyPart; -import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntity; -import org.apache.http.entity.mime.content.ContentBody; import org.apache.http.entity.mime.content.StringBody; -import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; +import org.apache.http.util.EntityUtils; import org.envaya.kalsms.App; import org.envaya.kalsms.Base64Coder; import org.envaya.kalsms.OutgoingMessage; @@ -53,6 +46,8 @@ public class HttpTask extends AsyncTask { private List formParts; private boolean useMultipartPost = false; + private HttpPost post; + public HttpTask(App app, BasicNameValuePair... paramsArr) { super(); @@ -67,15 +62,7 @@ public class HttpTask extends AsyncTask { { useMultipartPost = true; this.formParts = formParts; - } - - public HttpClient getHttpClient() - { - HttpParams httpParameters = new BasicHttpParams(); - HttpConnectionParams.setConnectionTimeout(httpParameters, 8000); - HttpConnectionParams.setSoTimeout(httpParameters, 8000); - return new DefaultHttpClient(httpParameters); - } + } private String getSignature() throws NoSuchAlgorithmException, UnsupportedEncodingException @@ -110,16 +97,15 @@ public class HttpTask extends AsyncTask { } protected HttpResponse doInBackground(String... ignored) { + if (url.length() == 0) { + app.log("Can't contact server; Server URL not set"); + return null; + } + + post = new HttpPost(url); + try - { - if (url.length() == 0) { - app.log("Can't contact server; Server URL not set"); - return null; - } - - HttpPost post = new HttpPost(url); - - + { if (useMultipartPost) { MultipartEntity entity = new MultipartEntity();//HttpMultipartMode.BROWSER_COMPATIBLE); @@ -144,9 +130,9 @@ public class HttpTask extends AsyncTask { post.setHeader("X-Kalsms-Signature", signature); - HttpClient client = getHttpClient(); + HttpClient client = app.getHttpClient(); HttpResponse response = client.execute(post); - + int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == 200) { @@ -154,29 +140,32 @@ public class HttpTask extends AsyncTask { } else if (statusCode == 403) { + response.getEntity().consumeContent(); app.log("Failed to authenticate to server"); app.log("(Phone number or password may be incorrect)"); return null; } else { + response.getEntity().consumeContent(); app.log("Received HTTP " + statusCode + " from server"); return null; } } catch (IOException ex) { + post.abort(); app.logError("Error while contacting server", ex); return null; } catch (Throwable ex) { + post.abort(); app.logError("Unexpected error while contacting server", ex, true); return null; - } - + } } - + protected String getDefaultToAddress() { return ""; @@ -224,6 +213,7 @@ public class HttpTask extends AsyncTask { } catch (Throwable ex) { + post.abort(); app.logError("Error processing server response", ex); handleFailure(); } @@ -236,6 +226,10 @@ public class HttpTask extends AsyncTask { protected void handleResponse(HttpResponse response) throws Exception { + if (response != null) + { + response.getEntity().consumeContent(); + } } protected void handleFailure()