PageRenderTime 33ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 1ms

/gwtrpccommlayer/src/main/java/com/googlecode/gwtrpccommlayer/server/GwtRpcCommLayerServlet.java

https://code.google.com/p/gwtrpccommlayer/
Java | 341 lines | 181 code | 44 blank | 116 comment | 17 complexity | 25e9e97ce4b892c388cd13bb08251965 MD5 | raw file
  1. /*
  2. * Copyright 2010 Jeff McHugh (Segue Development LLC)
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
  5. * in compliance with the License. You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software distributed under the License
  10. * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  11. * or implied. See the License for the specific language governing permissions and limitations under
  12. * the License.
  13. */
  14. package com.googlecode.gwtrpccommlayer.server;
  15. import com.google.gwt.user.server.rpc.RemoteServiceServlet;
  16. import com.googlecode.gwtrpccommlayer.shared.GwtRpcCommLayerPojoConstants;
  17. import com.googlecode.gwtrpccommlayer.shared.GwtRpcCommLayerPojoRequest;
  18. import com.googlecode.gwtrpccommlayer.shared.GwtRpcCommLayerPojoResponse;
  19. import javax.servlet.ServletConfig;
  20. import javax.servlet.ServletException;
  21. import javax.servlet.ServletRequest;
  22. import javax.servlet.ServletResponse;
  23. import javax.servlet.http.HttpServletRequest;
  24. import javax.servlet.http.HttpServletResponse;
  25. import java.io.*;
  26. import java.lang.reflect.InvocationTargetException;
  27. import java.lang.reflect.Method;
  28. import java.util.LinkedList;
  29. /**
  30. * This class can either sit above your servlet (i.e. your servlet extends this) or it can wrap
  31. * your servlet (i.e. it will receive the calls and delegate it to the respective methods
  32. * @author jeff mchugh
  33. *
  34. */
  35. public class GwtRpcCommLayerServlet extends RemoteServiceServlet
  36. {
  37. private static final long serialVersionUID = -8829760243946113688L;
  38. Object servletInstance = null;
  39. public GwtRpcCommLayerServlet() { }
  40. //@Inject
  41. //Can be extended and injected Guice
  42. public GwtRpcCommLayerServlet(Object servletImplementation)
  43. {
  44. this.servletInstance = servletImplementation;
  45. //this.servletImplementation = servletImplementation;
  46. }
  47. /**
  48. * Initializes the servlet
  49. */
  50. public void init(ServletConfig config) throws ServletException
  51. {
  52. super.init(config);
  53. /*
  54. * The default is to assume this instance is the selected servlet
  55. */
  56. servletInstance = this;
  57. /*
  58. * Check to see another servlet should be the target
  59. */
  60. //todo: this is currently configured using an init param in web.xml. We need to change this to use something guice-friendly!
  61. //maybe use @Inject(optional=true) @Named("CommLayerImplClass") String strImplmentationClass;
  62. String servletImplClassName = config.getInitParameter(GwtRpcCommLayerPojoConstants.GWT_RPC_COMM_LAYER_SERVLET_IMPL_CLASS);
  63. //Use guice injected name instead of init parameter
  64. //if ( servletImplementation != null)
  65. if ( servletImplClassName != null && !servletImplClassName.trim().equals(""))
  66. {
  67. try
  68. {
  69. Class clzz = Class.forName(servletImplClassName);
  70. servletInstance = clzz.newInstance();
  71. }
  72. catch(Throwable t)
  73. {
  74. throw new ServletException(t);
  75. }
  76. }
  77. }
  78. /**
  79. * any servlet that extends can opt to deny these request
  80. * either explicitly or using web.xml
  81. * @return
  82. */
  83. protected boolean allowGwtRpcPojoRequest()
  84. {
  85. return true;
  86. }
  87. protected void initalizePerRequestPerResponseIfNeeded()
  88. {
  89. if ( super.perThreadRequest == null )
  90. {
  91. super.perThreadRequest = new ThreadLocal<HttpServletRequest>();
  92. }
  93. if ( super.perThreadResponse == null )
  94. {
  95. super.perThreadResponse = new ThreadLocal<HttpServletResponse>();
  96. }
  97. }
  98. /**
  99. * Override the main service call and implement the special handling here
  100. */
  101. public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException
  102. {
  103. HttpServletRequest request = (HttpServletRequest) req;
  104. HttpServletResponse response = (HttpServletResponse) resp;
  105. /*
  106. * If the GwtRpcCommLayerClient has made this request, this header should be provided
  107. */
  108. String gwtClientUserAgent = request.getHeader(GwtRpcCommLayerPojoConstants.GWT_RPC_COMM_LAYER_CLIENT_KEY);
  109. /*
  110. * Only execute this block if:
  111. * - allowGwtRpcPojoRequest() is true
  112. * - is POST
  113. * - gwtClientUserAgent = 'GwtRpcCommLayerPojoRequest'
  114. */
  115. if ( allowGwtRpcPojoRequest()
  116. && request.getMethod().equals("POST")
  117. && gwtClientUserAgent != null
  118. && gwtClientUserAgent.equalsIgnoreCase(GwtRpcCommLayerPojoConstants.GWT_RPC_COMM_LAYER_POJO_CLIENT))
  119. {
  120. try
  121. {
  122. /*
  123. * This might not be initialized.
  124. * So do it if needed
  125. */
  126. initalizePerRequestPerResponseIfNeeded();
  127. super.perThreadRequest.set(request);
  128. super.perThreadResponse.set(response);
  129. doServicePojoRequest(request,response);
  130. }
  131. finally
  132. {
  133. super.perThreadRequest.set(null);
  134. super.perThreadResponse.set(null);
  135. }
  136. }
  137. else
  138. {
  139. /*
  140. * Call up the chain and allow one of the implementations handle the request accordingly.
  141. * For an
  142. */
  143. super.service(req, resp);
  144. }
  145. }
  146. /**
  147. * Reads the request's InputStream and cast it to the correct Object type(s)
  148. * @param req
  149. * @param resp
  150. * @throws ServletException
  151. * @throws IOException
  152. */
  153. public void doServicePojoRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
  154. {
  155. /*
  156. * The bytes that have been provided as the "POST" data
  157. * represent a serialized POJO
  158. *
  159. * read it and store it into a buffer (ByteArrayOutputStream)
  160. */
  161. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  162. InputStream in = req.getInputStream();
  163. byte[] buff = new byte[1024];
  164. while(true)
  165. {
  166. int len = in.read(buff);
  167. //todo:is the ByteArrayOutputStream necessary? could just use: ObjectInputStream input = new ObjectInputStream(in);
  168. if ( len == -1 )
  169. {
  170. break;
  171. }
  172. bos.write(buff, 0, len);
  173. }
  174. if ( bos.toByteArray().length > 0 )
  175. {
  176. try
  177. {
  178. ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
  179. Serializable ser = (Serializable) objIn.readObject();
  180. if ( ser instanceof GwtRpcCommLayerPojoRequest)
  181. {
  182. GwtRpcCommLayerPojoRequest rpcPojoReq = (GwtRpcCommLayerPojoRequest) ser;
  183. executePojoRequest(rpcPojoReq, req, resp);
  184. }
  185. else
  186. {
  187. throw new ServletException("POST data does not cast to an instance of GwtRpcCommLayerPojoRequest");
  188. }
  189. }
  190. catch(Throwable t)
  191. {
  192. throw new ServletException("Exception thrown executing pojo request.", t);
  193. }
  194. }
  195. else
  196. {
  197. throw new ServletException("POST data does not contain any serialized bytes.");
  198. }
  199. }
  200. /**
  201. * Execute the actual method within the GwtRpc servlet
  202. * @param pojoRequest
  203. * @param req
  204. * @param resp
  205. * @throws Throwable
  206. */
  207. public void executePojoRequest(GwtRpcCommLayerPojoRequest pojoRequest,HttpServletRequest req, HttpServletResponse resp) throws Throwable
  208. {
  209. try
  210. {
  211. /*
  212. * extract the appropriate method
  213. */
  214. Method method = getMethod(pojoRequest);
  215. /*
  216. * invoke the method
  217. */
  218. Object returnedInstance = invokeMethod(pojoRequest, method);
  219. /*
  220. * wrap response within a response object
  221. */
  222. GwtRpcCommLayerPojoResponse pojoResp = new GwtRpcCommLayerPojoResponse();
  223. pojoResp.setResponseInstance( (Serializable) returnedInstance);
  224. /*
  225. * send back the result as a stream set of bytes
  226. */
  227. serializeResponse(req,resp,pojoRequest,pojoResp);
  228. }
  229. catch(NoSuchMethodException e)
  230. {
  231. log("Method does not found.", e);
  232. resp.sendError(500, e.toString() );
  233. }
  234. catch(InvocationTargetException e)
  235. {
  236. log("Error executing method.", e.getCause());
  237. resp.sendError(500, e.toString() );
  238. }
  239. catch(IllegalAccessException e)
  240. {
  241. log("Error accessing method.", e);
  242. resp.sendError(500, e.toString() );
  243. }
  244. }
  245. /**
  246. * Write the appropriate response
  247. * @param req
  248. * @param resp
  249. * @param pojoRequest
  250. * @param pojoResp
  251. * @throws IOException
  252. */
  253. protected void serializeResponse(HttpServletRequest req, HttpServletResponse resp, GwtRpcCommLayerPojoRequest pojoRequest, GwtRpcCommLayerPojoResponse pojoResp) throws IOException
  254. {
  255. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  256. ObjectOutputStream objOut = new ObjectOutputStream(bos);
  257. objOut.writeObject(pojoResp);
  258. objOut.flush();
  259. objOut.close();
  260. resp.setContentType("binary/octet-stream");
  261. resp.setContentLength(bos.toByteArray().length);
  262. OutputStream out = resp.getOutputStream();
  263. out.write(bos.toByteArray());
  264. out.flush();
  265. }
  266. /**
  267. *
  268. * @param stressTestRequest
  269. * @return
  270. * @throws NoSuchMethodException
  271. */
  272. protected Method getMethod(GwtRpcCommLayerPojoRequest stressTestRequest) throws NoSuchMethodException, ClassNotFoundException {
  273. int count = 0;
  274. Class<?> paramClasses[] = new Class[stressTestRequest.getMethodParameters().size()];
  275. LinkedList<Class<?>> lstParameterClasses = new LinkedList<Class<?>>();
  276. for (String methodName: stressTestRequest.getParameterClassNames()) {
  277. lstParameterClasses.add(Class.forName(methodName));
  278. }
  279. Class[] arrParameterClasses = lstParameterClasses.toArray(new Class[0]);
  280. return getClass().getMethod(stressTestRequest.getMethodName(), arrParameterClasses);
  281. }
  282. /**
  283. *
  284. * @param stressTestRequest
  285. * @param method
  286. * @return
  287. * @throws InvocationTargetException
  288. * @throws IllegalAccessException
  289. */
  290. protected Object invokeMethod(GwtRpcCommLayerPojoRequest stressTestRequest, Method method) throws InvocationTargetException, IllegalAccessException
  291. {
  292. //todo: call toArray with correct size Object Array
  293. Object paramsAsObjects[] = stressTestRequest.getMethodParameters().toArray( new Object[0]);
  294. Object instance = method.invoke(servletInstance, paramsAsObjects);
  295. return instance;
  296. }
  297. }