PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/andrico/src/org/andrico/andjax/http/HttpClientService.java

http://andrico.googlecode.com/
Java | 353 lines | 152 code | 40 blank | 161 comment | 12 complexity | ce59f10f4eecf41d1d01c72d7420f624 MD5 | raw file
  1. /***************************************************************************
  2. * Copyright (C) 2009 Andrico Team *
  3. * http://code.google.com/p/andrico/ *
  4. * *
  5. * Licensed under the Apache License, Version 2.0 (the "License"); *
  6. * you may not use this file except in compliance with the License. *
  7. * *
  8. * You may obtain a copy of the License at *
  9. * http://www.apache.org/licenses/LICENSE-2.0 *
  10. * *
  11. * Unless required by applicable law or agreed to in writing, software *
  12. * distributed under the License is distributed on an "AS IS" BASIS, *
  13. * *
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  15. * See the License for the specific language governing permissions and *
  16. * limitations under the License. *
  17. ****************************************************************************/
  18. /* Licensed under the Apache License, Version 2.0 (the "License");
  19. * you may not use this file except in compliance with the License.
  20. * You may obtain a copy of the License at
  21. *
  22. * http://www.apache.org/licenses/LICENSE-2.0
  23. *
  24. * Unless required by applicable law or agreed to in writing, software
  25. * distributed under the License is distributed on an "AS IS" BASIS,
  26. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  27. * See the License for the specific language governing permissions and
  28. * limitations under the License.
  29. */
  30. package org.andrico.andjax.http;
  31. import org.apache.http.HttpMessage;
  32. import org.apache.http.HttpResponse;
  33. import org.apache.http.HttpVersion;
  34. import org.apache.http.client.ClientProtocolException;
  35. import org.apache.http.client.HttpClient;
  36. import org.apache.http.client.methods.HttpUriRequest;
  37. import org.apache.http.conn.ClientConnectionManager;
  38. import org.apache.http.conn.scheme.PlainSocketFactory;
  39. import org.apache.http.conn.scheme.Scheme;
  40. import org.apache.http.conn.scheme.SchemeRegistry;
  41. import org.apache.http.conn.scheme.SocketFactory;
  42. import org.apache.http.entity.mime.MultipartEntity;
  43. import org.apache.http.impl.client.DefaultHttpClient;
  44. import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
  45. import org.apache.http.params.BasicHttpParams;
  46. import org.apache.http.params.HttpParams;
  47. import org.apache.http.params.HttpProtocolParams;
  48. import android.util.Log;
  49. import java.io.IOException;
  50. import java.net.URISyntaxException;
  51. import java.util.Map;
  52. import java.util.concurrent.Callable;
  53. import java.util.concurrent.ExecutorService;
  54. import java.util.concurrent.Executors;
  55. /*
  56. * Handle http connections.
  57. *
  58. * Make asynchronous http requests with Future actions. We support two threads because historically, thats all browsers
  59. * are allowed to pull from per domain. Since we're only touching one domain, this matches that expectation
  60. *
  61. * @author jlapenna@gmail.com (Joe LaPenna)
  62. *
  63. */
  64. public class HttpClientService {
  65. /**
  66. * Encapsulates the http request in a runnable to be executed. When called,
  67. * the passed httpRequest will be executed by the HttpClientService
  68. * instance's executor.
  69. *
  70. * @author jlapenna
  71. */
  72. private class HttpMessageCallable implements Callable<HttpResponse> {
  73. private static final String LOG = "HttpMessageCallable";
  74. private final HttpMessage mHttpRequest;
  75. /**
  76. * @param httpRequest The http request that will be executed when this
  77. * is called.
  78. */
  79. public HttpMessageCallable(HttpMessage httpRequest) {
  80. this.mHttpRequest = httpRequest;
  81. }
  82. /*
  83. * When called, the http message will be executed by the
  84. * HttpClientService's http client.
  85. * @return HttpResponse The result of the http request.
  86. */
  87. public HttpResponse call() throws Exception {
  88. try {
  89. return HttpClientService.this.mHttpClient
  90. .execute((HttpUriRequest)this.mHttpRequest);
  91. } catch (final Exception e) {
  92. Log.d(LOG, "call caused an exception.", e);
  93. throw e;
  94. }
  95. }
  96. }
  97. public static final String TAG = "HttpClientService";
  98. /**
  99. * The thread executor.
  100. */
  101. private ExecutorService mExecutorService;
  102. /**
  103. * Shard http client.
  104. */
  105. private HttpClient mHttpClient;
  106. /**
  107. * The factory used to generate http requests for this service.
  108. */
  109. private final HttpMessageFactory mHttpMessageFactory;
  110. private final String mCookieDomain;
  111. private final int mPoolSize;
  112. /**
  113. * Construct the HttpClientService
  114. *
  115. * @param poolSize The number of threads allowed to exist at once.
  116. * @param cookieDomain I'm not quite sure what I'm doing with this. figure
  117. * it out.
  118. */
  119. public HttpClientService(int poolSize, String cookieDomain) {
  120. mPoolSize = poolSize;
  121. mCookieDomain = cookieDomain;
  122. // Handles generating HttpRequests.
  123. this.mHttpMessageFactory = new HttpMessageFactory(mCookieDomain);
  124. start();
  125. }
  126. public synchronized void stop() {
  127. assertState();
  128. if (isRunning()) {
  129. this.mHttpClient.getConnectionManager().shutdown();
  130. this.mHttpClient = null;
  131. this.mExecutorService.shutdown();
  132. this.mExecutorService = null;
  133. }
  134. }
  135. public synchronized void start() {
  136. assertState();
  137. if (!isRunning()) {
  138. // Use the client defaults and create a client.
  139. this.mHttpClient = this.createHttpClient();
  140. // Sets up the thread pool part of the service.
  141. this.mExecutorService = Executors.newFixedThreadPool(mPoolSize);
  142. }
  143. }
  144. public synchronized boolean isRunning() {
  145. assertState();
  146. return this.mHttpClient != null && this.mExecutorService != null;
  147. }
  148. private void assertState() {
  149. assert (this.mHttpClient != null && this.mExecutorService != null)
  150. || (this.mHttpClient == null && this.mExecutorService == null);
  151. }
  152. /**
  153. * Create a thread-safe client.
  154. *
  155. * @return HttpClient
  156. */
  157. private final HttpClient createHttpClient() {
  158. // Sets up the http part of the service.
  159. final SchemeRegistry supportedSchemes = new SchemeRegistry();
  160. // Register the "http" protocol scheme, it is required
  161. // by the default operator to look up socket factories.
  162. final SocketFactory sf = PlainSocketFactory.getSocketFactory();
  163. supportedSchemes.register(new Scheme("http", sf, 80));
  164. // Set some client http client parameter defaults.
  165. final HttpParams httpParams = this.createHttpParams();
  166. final ClientConnectionManager ccm = new ThreadSafeClientConnManager(httpParams,
  167. supportedSchemes);
  168. return new DefaultHttpClient(ccm, httpParams);
  169. }
  170. /**
  171. * Create the default HTTP protocol parameters.
  172. */
  173. private final HttpParams createHttpParams() {
  174. // prepare parameters
  175. final HttpParams params = new BasicHttpParams();
  176. HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
  177. HttpProtocolParams.setContentCharset(params, "UTF-8");
  178. HttpProtocolParams.setUseExpectContinue(params, true);
  179. return params;
  180. }
  181. private HttpResponse execute(final HttpMessage httpMessage) {
  182. try {
  183. return this.mHttpClient.execute((HttpUriRequest)httpMessage);
  184. } catch (ClientProtocolException e) {
  185. // TODO Auto-generated catch block
  186. e.printStackTrace();
  187. } catch (IOException e) {
  188. // TODO Auto-generated catch block
  189. e.printStackTrace();
  190. }
  191. return null;
  192. }
  193. /**
  194. * Execute an http request, calling the runnable after. Right now this is
  195. * limited in that you can only pass one value per key in the http post.
  196. * (The Map is the limiter).
  197. *
  198. * @param url The url to access
  199. * @param responseRunnable The runnable to execute upon http request
  200. * completion.
  201. * @throws URISyntaxException
  202. */
  203. public HttpResponse execute(String url) throws URISyntaxException {
  204. final HttpMessage httpMessage = this.mHttpMessageFactory.create(url, null);
  205. return execute(httpMessage);
  206. }
  207. /**
  208. * Execute an http request, calling the runnable after. Right now this is
  209. * limited in that you can only pass one value per key in the http post.
  210. * (The Map is the limiter).
  211. *
  212. * @param url The url to access
  213. * @param params The POST parameters to pass to this request.
  214. * @throws URISyntaxException
  215. */
  216. public HttpResponse execute(String url, Map<String, String> params) throws URISyntaxException {
  217. Log.d(TAG, "Executing");
  218. final HttpMessage httpMessage = this.mHttpMessageFactory.create(url, params);
  219. return execute(httpMessage);
  220. }
  221. /**
  222. * Execute an http request, calling the runnable after. Right now this is
  223. * limited in that you can only pass one value per key in the http post.
  224. * (The Map is the limiter).
  225. *
  226. * @param url The url to access
  227. * @param multipartEntity The POST parameters to pass to this request.
  228. * @throws URISyntaxException
  229. */
  230. public HttpResponse execute(String url, MultipartEntity multipartEntity)
  231. throws URISyntaxException {
  232. HttpMessage httpMessage = this.mHttpMessageFactory.createFromParts(url, multipartEntity);
  233. return this.execute(httpMessage);
  234. }
  235. @Override
  236. public void finalize() {
  237. this.mExecutorService.shutdownNow();
  238. }
  239. /**
  240. * Put this HttpChainingRunnable that is composed of a HttpMessageCallable
  241. * and HttpChainingRunnable on the queue to be executed. Upon completion of
  242. * the http request, call the runnable. Right now this is limited in that
  243. * you can only pass one value per key in the http post. (The Map is the
  244. * limiter).
  245. *
  246. * @param chainingRunnable The runnable that will cause a runnable to be
  247. * called when an http request completes.
  248. */
  249. private void submit(HttpChainingRunnable chainingRunnable) {
  250. this.mExecutorService.submit(chainingRunnable);
  251. }
  252. /**
  253. * Put an http request on the queue to be executed. Upon completion of the
  254. * http request, a runnable will be called. Right now this is limited in
  255. * that you can only pass one value per key in the http post. (The Map is
  256. * the limiter).
  257. *
  258. * @param url The url to access.
  259. * @param responseRunnable The runnable to execute upon http request
  260. * completion.
  261. * @throws URISyntaxException
  262. */
  263. public void submit(String url, IHttpResponseRunnable responseRunnable)
  264. throws URISyntaxException {
  265. final HttpMessage httpMessage = this.mHttpMessageFactory.create(url, null);
  266. this
  267. .submit(new HttpChainingRunnable(new HttpMessageCallable(httpMessage),
  268. responseRunnable));
  269. }
  270. /**
  271. * Put an http request on the queue to be executed. Upon completion of the
  272. * http request, a runnable will be called. Right now this is limited in
  273. * that you can only pass one value per key in the http post. (The Map is
  274. * the limiter).
  275. *
  276. * @param url The url to access
  277. * @param params The POST parameters to pass to this request.
  278. * @param responseRunnable The runnable to execute upon http request
  279. * completion.
  280. * @throws URISyntaxException
  281. */
  282. public void submit(String url, Map<String, String> params,
  283. IHttpResponseRunnable responseRunnable) throws URISyntaxException {
  284. final HttpMessage httpMessage = this.mHttpMessageFactory.create(url, params);
  285. this
  286. .submit(new HttpChainingRunnable(new HttpMessageCallable(httpMessage),
  287. responseRunnable));
  288. }
  289. /**
  290. * Put an http request on the queue to be executed. Upon completion of the
  291. * http request, a runnable will be called. Right now this is limited in
  292. * that you can only pass one value per key in the http post. (The Map is
  293. * the limiter).
  294. *
  295. * @param url The url to access.
  296. * @param multipartEntity The POST parameters to pass to this request.
  297. * @param responseRunnable The runnable to execute upon http request
  298. * completion.
  299. * @throws URISyntaxException
  300. */
  301. public void submit(String url, MultipartEntity multipartEntity,
  302. IHttpResponseRunnable responseRunnable) throws URISyntaxException {
  303. Log.d(TAG, "submitting multipartentity dodad");
  304. HttpMessage httpMessage;
  305. httpMessage = this.mHttpMessageFactory.createFromParts(url, multipartEntity);
  306. Log.d(TAG, "Posting multipartEntity" + multipartEntity.toString());
  307. Log.d(TAG, String.valueOf(multipartEntity.getContentLength()));
  308. Log.d(TAG, multipartEntity.toString());
  309. this
  310. .submit(new HttpChainingRunnable(new HttpMessageCallable(httpMessage),
  311. responseRunnable));
  312. }
  313. }