PageRenderTime 35ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/gwtrpccommlayer/src/main/java/com/googlecode/gwtrpccommlayer/client/impl/ProxyImpl.java

https://code.google.com/p/gwtrpccommlayer/
Java | 521 lines | 327 code | 83 blank | 111 comment | 50 complexity | 715a7963e932a198ec7e5e43a9454790 MD5 | raw file
  1. package com.googlecode.gwtrpccommlayer.client.impl;
  2. import com.google.gwt.user.client.rpc.AsyncCallback;
  3. import com.google.inject.Inject;
  4. import com.google.inject.assistedinject.Assisted;
  5. import com.googlecode.gwtrpccommlayer.client.function.ResponseSerializer;
  6. import com.googlecode.gwtrpccommlayer.shared.GwtRpcCommLayerPojoConstants;
  7. import com.googlecode.gwtrpccommlayer.shared.GwtRpcCommLayerPojoRequest;
  8. import com.googlecode.gwtrpccommlayer.shared.GwtRpcCommLayerPojoResponse;
  9. import org.apache.http.Header;
  10. import org.apache.http.HttpEntity;
  11. import org.apache.http.HttpResponse;
  12. import org.apache.http.client.methods.HttpPost;
  13. import org.apache.http.cookie.Cookie;
  14. import org.apache.http.entity.InputStreamEntity;
  15. import org.apache.http.impl.client.DefaultHttpClient;
  16. import javax.xml.ws.Response;
  17. import java.io.*;
  18. import java.lang.reflect.Method;
  19. import java.net.URL;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. /**
  23. * Created by IntelliJ IDEA.
  24. * User: dan
  25. * Date: 10/30/10
  26. * Time: 10:04 PM
  27. */
  28. public class ProxyImpl implements IGwtRpcClientSideProxy{
  29. static int DEFAULT_STANDARD_PORT = 80;
  30. static int DEFAULT_SECURE_PORT = 443;
  31. private HashMap<String,Cookie> cookies = null;
  32. private boolean showResponseHeaders = false;
  33. private final ResponseSerializer responseSerializer;
  34. private URL url;
  35. @Inject
  36. public ProxyImpl(ResponseSerializer responseSerializer, URL url, @Assisted HashMap<String,Cookie> cookies) {
  37. this.responseSerializer = responseSerializer;
  38. this.url = url;
  39. this.cookies = cookies;
  40. }
  41. boolean doesListIncludeGwtAsynchCallback(Class[] interfaces)
  42. {
  43. Class target = AsyncCallback.class;
  44. for (Class intf : interfaces)
  45. {
  46. if ( intf.getName().equals(target.getName()))
  47. {
  48. return true;
  49. }
  50. }
  51. return false;
  52. }
  53. Object invoke_asynchronousMode(Object proxy, Method method, Object[] args) throws Throwable
  54. {
  55. if ( args.length == 0 )
  56. {
  57. throw new RuntimeException("A minimum of (1) object is required for asynchronous mode");
  58. }
  59. AsyncCallback theCallback = (AsyncCallback) args[args.length-1];
  60. /*
  61. * Wrap the Method (and Method arguments)
  62. */
  63. GwtRpcCommLayerPojoRequest pojoRequest = new GwtRpcCommLayerPojoRequest();
  64. pojoRequest.setMethodName(method.getName());
  65. if ( args != null )
  66. {
  67. for (Object object : args)
  68. {
  69. if ( object != theCallback )//the last object is always going to be the callback implementation
  70. {
  71. pojoRequest.getMethodParameters().add( (Serializable) object);
  72. }
  73. }
  74. }
  75. /*
  76. * This block now makes it possible to execute in a "asynchronous" mode
  77. */
  78. GwtRpcCommLayerPojoResponse pojoResp = null;
  79. try
  80. {
  81. pojoResp = executeRequest(pojoRequest);
  82. if ( pojoResp != null )
  83. {
  84. Object result = pojoResp.getResponseInstance();
  85. AsynchCallBackRunnable runnable = new AsynchCallBackRunnable(theCallback, result);
  86. Thread thread = new Thread(runnable);
  87. thread.start();
  88. return null;
  89. }
  90. else
  91. {
  92. throw new RuntimeException("No valid GwtRpcCommLayerPojoResponse returned. Check for http errors in log.");
  93. }
  94. }
  95. catch(Throwable caught)
  96. {
  97. AsynchCallBackRunnable runnable = new AsynchCallBackRunnable(theCallback, caught);
  98. Thread thread = new Thread(runnable);
  99. thread.start();
  100. return null;
  101. }
  102. }
  103. Object invoke_synchronousMode(Object proxy, Method method, Object[] args) throws Throwable
  104. {
  105. /*
  106. * Wrap the Method (and Method arguments)
  107. */
  108. GwtRpcCommLayerPojoRequest pojoRequest = new GwtRpcCommLayerPojoRequest();
  109. pojoRequest.setMethodName(method.getName());
  110. if ( args != null )
  111. {
  112. for (Object object : args)
  113. {
  114. //pojoRequest.getMethodParameters().add( (Serializable) object);
  115. pojoRequest.getMethodParameters().add( object.getClass());
  116. }
  117. }
  118. /*
  119. * This is the original block of code that executed for the "synchronous" mode
  120. */
  121. GwtRpcCommLayerPojoResponse pojoResp = executeRequest(pojoRequest);
  122. if ( pojoResp != null )
  123. {
  124. return pojoResp.getResponseInstance();
  125. }
  126. else
  127. {
  128. throw new RuntimeException("No valid GwtRpcCommLayerPojoResponse returned. Check for http errors in log.");
  129. }
  130. }
  131. @Override
  132. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  133. {
  134. int mode = 0;//default to synchronous mode
  135. if ( args != null && args.length > 0 )
  136. {
  137. Object last = args[args.length-1];
  138. if ( doesListIncludeGwtAsynchCallback(last.getClass().getInterfaces()))
  139. {
  140. mode = 1;
  141. }
  142. }
  143. if ( mode == 0 )
  144. {
  145. return invoke_synchronousMode(proxy, method, args);
  146. }
  147. else
  148. {
  149. return invoke_asynchronousMode(proxy, method, args);
  150. }
  151. }
  152. /**
  153. * The URL that this client shall interact with
  154. */
  155. public void setUrl(URL url)
  156. {
  157. }
  158. /**
  159. * Set this to true for debugging
  160. */
  161. public void setShowResponseHeaders(boolean b)
  162. {
  163. this.showResponseHeaders = b;
  164. }
  165. /**
  166. * Main method that executes to make call to remote server
  167. * this method uses an HTTP POST method and can keep state if needed (using cookies)
  168. * @throws IOException
  169. */
  170. protected synchronized GwtRpcCommLayerPojoResponse executeRequest(GwtRpcCommLayerPojoRequest pojoRequest) throws IOException
  171. {
  172. /*
  173. * Create HTTP CLIENT
  174. */
  175. DefaultHttpClient httpclient = new DefaultHttpClient();
  176. /*
  177. * Add Cookies to the request
  178. * this enables a state-full set of transactions
  179. * to take place. While this is NOT required for the
  180. * GwtRpcCommLayer framework, the actually developer might have this
  181. * requirement embedded into his/her servlet(s) and thus
  182. * this makes to possible to communicate just like
  183. * a browser would
  184. *
  185. */
  186. if ( getCookies().size() > 0 )
  187. {
  188. for (Cookie cookie : getCookies().values())
  189. {
  190. httpclient.getCookieStore().addCookie(cookie);
  191. }
  192. }
  193. /*
  194. * SERIALZED THE POJO-REQUEST OBJECT INTO BYTES
  195. */
  196. byte[] pojoByteArray = serializeIntoBytes(pojoRequest);
  197. long length = pojoByteArray.length;
  198. ByteArrayInputStream in = new ByteArrayInputStream(pojoByteArray);
  199. InputStreamEntity reqEntity = new InputStreamEntity(in, length);
  200. reqEntity.setContentType("binary/octet-stream");
  201. reqEntity.setChunked(false);
  202. /*
  203. * CONSTRUCT THE URL
  204. */
  205. String url = createFullyQualifiedURL();
  206. /*
  207. * Create POST instance
  208. */
  209. HttpPost httppost = new HttpPost(url);
  210. httppost.setEntity(reqEntity);
  211. /*
  212. * Add the correct user-agent
  213. */
  214. httppost.addHeader(GwtRpcCommLayerPojoConstants.GWT_RPC_COMM_LAYER_CLIENT_KEY, GwtRpcCommLayerPojoConstants.GWT_RPC_COMM_LAYER_POJO_CLIENT);
  215. /*
  216. * Notify any last minute listener
  217. */
  218. onBeforeRequest(httppost);
  219. HttpResponse response = httpclient.execute(httppost);
  220. //return
  221. /*
  222. * Provide a call back for timing, error handling, etc
  223. */
  224. onAfterRequest(httppost, response);
  225. /*
  226. * Check for server error
  227. */
  228. if ( response.getStatusLine().getStatusCode() >= 400 && response.getStatusLine().getStatusCode() <= 599 )
  229. {
  230. onResponseError(response.getStatusLine().getStatusCode(), response);
  231. return null;
  232. }
  233. else if (response.getFirstHeader("Content-Type") != null && !response.getFirstHeader("Content-Type").getValue().equals("binary/octet-stream"))
  234. {
  235. onResponseError("Content-Type must be 'binary/octet-stream'");
  236. return null;
  237. }
  238. else
  239. {
  240. /*
  241. * Provide a call-back for examining the response headers
  242. */
  243. if ( isShowResponseHeaders() && response.getAllHeaders() != null )
  244. {
  245. dumpResponseHeaders(response.getAllHeaders());
  246. }
  247. /*
  248. * Provide a call-back for examining the response cookies
  249. */
  250. List<Cookie> cookies = httpclient.getCookieStore().getCookies();
  251. if ( cookies != null )
  252. {
  253. recordCookies(cookies);
  254. }
  255. HttpEntity resEntity = response.getEntity();
  256. byte[] respData = deserializeIntoBytes(resEntity);
  257. try
  258. {
  259. GwtRpcCommLayerPojoResponse pojoResp = createInstanceFromBytes(respData);
  260. return pojoResp;
  261. }
  262. catch(ClassNotFoundException e)
  263. {
  264. throw new IOException(e);
  265. }
  266. }
  267. }
  268. /*
  269. * ---------------- METHODS THAT CAN BE EXTENDED BY SUB-CLASSES -------------
  270. */
  271. protected String createFullyQualifiedURL()
  272. {
  273. /*
  274. * Configure the URL and PATH
  275. */
  276. StringBuffer buff = new StringBuffer();
  277. buff.append(url.getProtocol());
  278. buff.append("://");
  279. buff.append(url.getHost());
  280. if ( url.getPort() != DEFAULT_STANDARD_PORT && url.getPort() != DEFAULT_SECURE_PORT )
  281. {
  282. buff.append(":"+url.getPort());
  283. }
  284. buff.append(url.getPath());
  285. if ( url.getQuery() != null )
  286. {
  287. buff.append("?");
  288. buff.append(url.getQuery());
  289. }
  290. return buff.toString();
  291. }
  292. protected byte[] serializeIntoBytes(GwtRpcCommLayerPojoRequest pojoRequest) throws IOException
  293. {
  294. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  295. ObjectOutputStream objOut = new ObjectOutputStream(bos);
  296. objOut.writeObject(pojoRequest);
  297. objOut.flush();
  298. objOut.close();
  299. byte[] all = bos.toByteArray();
  300. return all;
  301. }
  302. protected byte[] deserializeIntoBytes(HttpEntity respEntity ) throws IOException
  303. {
  304. byte[] b = new byte[512];
  305. ByteArrayOutputStream buff = new ByteArrayOutputStream();
  306. InputStream respIn = respEntity.getContent();
  307. while(true)
  308. {
  309. int vv = respIn.read(b);
  310. if ( vv == -1 )
  311. {
  312. break;
  313. }
  314. buff.write(b, 0, vv);
  315. }
  316. return buff.toByteArray();
  317. }
  318. protected GwtRpcCommLayerPojoResponse createInstanceFromBytes(byte[] data) throws IOException, ClassNotFoundException
  319. {
  320. ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(data));
  321. Object instance = objIn.readObject();
  322. GwtRpcCommLayerPojoResponse pojoResp = (GwtRpcCommLayerPojoResponse) instance;
  323. return pojoResp;
  324. }
  325. protected void recordCookies(List<Cookie> cookies)
  326. {
  327. for (Cookie cookie : cookies)
  328. {
  329. getCookies().put(cookie.getName(), cookie);
  330. }
  331. }
  332. protected void dumpResponseHeaders(Header header[])
  333. {
  334. for (Header header2 : header)
  335. {
  336. System.out.println("" + header2.getName() + ":" + header2.getValue() );
  337. }
  338. }
  339. /**
  340. * Provides a call-back for future functionality. Will get called before the actual HTTP Request is executed
  341. * @param httppost
  342. */
  343. protected void onBeforeRequest(HttpPost httppost)
  344. {
  345. }
  346. /**
  347. * Provides a call-back for future functionality. Will get called after the response is returned
  348. * @param httppost
  349. * @param response
  350. */
  351. protected void onAfterRequest(HttpPost httppost, HttpResponse response)
  352. {
  353. }
  354. /**
  355. * Called in the event of an HTTP Response Error (400 through 599)
  356. * @param errorCode
  357. * @param response
  358. */
  359. protected void onResponseError(int errorCode, HttpResponse response)
  360. {
  361. System.out.println("HTTP_ERROR code=" + errorCode + " " + response.getStatusLine().getReasonPhrase() );
  362. }
  363. /**
  364. * Called in the event of an general error outside of the http protocol
  365. * @param errorCode
  366. * @param response
  367. */
  368. protected void onResponseError(String error)
  369. {
  370. System.out.println("Response Error=" + error);
  371. }
  372. /*
  373. * ---------------------------- GETTER/SETTER METHODS ---------------------------
  374. */
  375. /**
  376. * @param cookies the cookies to set
  377. */
  378. public void setCookies(HashMap<String,Cookie> cookies)
  379. {
  380. this.cookies = cookies;
  381. }
  382. /**
  383. * @return the cookies
  384. */
  385. public HashMap<String,Cookie> getCookies()
  386. {
  387. return cookies;
  388. }
  389. /**
  390. * @return the showResponseHeaders
  391. */
  392. boolean isShowResponseHeaders()
  393. {
  394. return showResponseHeaders;
  395. }
  396. /*
  397. * This class is for use with the asynchronous mode
  398. */
  399. static class AsynchCallBackRunnable<T> implements Runnable
  400. {
  401. AsyncCallback<T> callback;
  402. Throwable caughtThrowable;
  403. T result;
  404. public AsynchCallBackRunnable(AsyncCallback<T> callback, T result)
  405. {
  406. this.callback = callback;
  407. this.result = result;
  408. }
  409. public AsynchCallBackRunnable(AsyncCallback<T> callback, Throwable caughtThrowable)
  410. {
  411. this.callback = callback;
  412. this.caughtThrowable = caughtThrowable;
  413. }
  414. public void run()
  415. {
  416. try
  417. {
  418. if ( this.result != null )
  419. {
  420. this.callback.onSuccess(this.result);
  421. }
  422. else if ( this.caughtThrowable != null )
  423. {
  424. this.callback.onFailure(this.caughtThrowable);
  425. }
  426. else
  427. {
  428. throw new RuntimeException("Both 'success' and 'failure' payload objects are null. This should never occur.");
  429. }
  430. }
  431. catch(Throwable caught)
  432. {
  433. System.err.println("Failure in Asynch dispatch thread. " + caught.toString() );
  434. caught.printStackTrace();
  435. }
  436. }
  437. }
  438. }