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

https://code.google.com/p/gwtrpccommlayer/ · Java · 297 lines · 145 code · 42 blank · 110 comment · 13 complexity · 9383e547dd4ee57b7d6af6d5b070c73b 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 abstract class AbstractGwtRpcCommLayerServlet extends RemoteServiceServlet
  36. {
  37. private static final long serialVersionUID = -8829760243946113688L;
  38. Object servletInstance = null;
  39. public AbstractGwtRpcCommLayerServlet() { }
  40. //@Inject
  41. //Can be extended and injected Guice
  42. public AbstractGwtRpcCommLayerServlet(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. //need some function intercept <ServletRequest,Boolean>
  104. HttpServletRequest request = (HttpServletRequest) req;
  105. HttpServletResponse response = (HttpServletResponse) resp;
  106. /*
  107. * If the GwtRpcCommLayerClient has made this request, this header should be provided
  108. */
  109. String gwtClientUserAgent = request.getHeader(GwtRpcCommLayerPojoConstants.GWT_RPC_COMM_LAYER_CLIENT_KEY);
  110. /*
  111. * Only execute this block if:
  112. * - allowGwtRpcPojoRequest() is true
  113. * - is POST
  114. * - gwtClientUserAgent = 'GwtRpcCommLayerPojoRequest'
  115. */
  116. if ( allowGwtRpcPojoRequest()
  117. && request.getMethod().equals("POST")
  118. && gwtClientUserAgent != null
  119. && gwtClientUserAgent.equalsIgnoreCase(GwtRpcCommLayerPojoConstants.GWT_RPC_COMM_LAYER_POJO_CLIENT))
  120. {
  121. try
  122. {
  123. /*
  124. * This might not be initialized.
  125. * So do it if needed
  126. */
  127. initalizePerRequestPerResponseIfNeeded();
  128. super.perThreadRequest.set(request);
  129. super.perThreadResponse.set(response);
  130. doServicePojoRequest(request,response);
  131. }
  132. finally
  133. {
  134. super.perThreadRequest.set(null);
  135. super.perThreadResponse.set(null);
  136. }
  137. }
  138. else
  139. {
  140. /*
  141. * Call up the chain and allow one of the implementations handle the request accordingly.
  142. * For an
  143. */
  144. super.service(req, resp);
  145. }
  146. }
  147. /**
  148. * Reads the request's InputStream and cast it to the correct Object type(s)
  149. * @param req
  150. * @param resp
  151. * @throws javax.servlet.ServletException
  152. * @throws java.io.IOException
  153. */
  154. protected abstract void doServicePojoRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
  155. protected Object getImplementation() {
  156. return this.servletInstance;
  157. }
  158. /**
  159. * Execute the actual method within the GwtRpc servlet
  160. * @param pojoRequest
  161. * @param req
  162. * @param resp
  163. * @throws Throwable
  164. */
  165. public void executePojoRequest(GwtRpcCommLayerPojoRequest pojoRequest,HttpServletRequest req, HttpServletResponse resp) throws Throwable
  166. {
  167. try
  168. {
  169. /*
  170. * extract the appropriate method
  171. */
  172. Method method = getMethod(pojoRequest);
  173. /*
  174. * invoke the method
  175. */
  176. Object returnedInstance = invokeMethod(pojoRequest, method);
  177. /*
  178. * wrap response within a response object
  179. */
  180. GwtRpcCommLayerPojoResponse pojoResp = new GwtRpcCommLayerPojoResponse();
  181. pojoResp.setResponseInstance( (Serializable) returnedInstance);
  182. /*
  183. * send back the result as a stream set of bytes
  184. */
  185. serializeResponse(req,resp,pojoRequest,pojoResp);
  186. }
  187. catch(NoSuchMethodException e)
  188. {
  189. log("Method does not found.", e);
  190. resp.sendError(500, e.toString() );
  191. }
  192. catch(InvocationTargetException e)
  193. {
  194. log("Error executing method.", e.getCause());
  195. resp.sendError(500, e.toString() );
  196. }
  197. catch(IllegalAccessException e)
  198. {
  199. log("Error accessing method.", e);
  200. resp.sendError(500, e.toString() );
  201. }
  202. }
  203. /**
  204. * Write the appropriate response
  205. * @param req
  206. * @param resp
  207. * @param pojoRequest
  208. * @param pojoResp
  209. * @throws java.io.IOException
  210. */
  211. protected void serializeResponse(HttpServletRequest req, HttpServletResponse resp, GwtRpcCommLayerPojoRequest pojoRequest, GwtRpcCommLayerPojoResponse pojoResp) throws IOException
  212. {
  213. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  214. ObjectOutputStream objOut = new ObjectOutputStream(bos);
  215. objOut.writeObject(pojoResp);
  216. objOut.flush();
  217. objOut.close();
  218. resp.setContentType("binary/octet-stream");
  219. resp.setContentLength(bos.toByteArray().length);
  220. OutputStream out = resp.getOutputStream();
  221. out.write(bos.toByteArray());
  222. out.flush();
  223. }
  224. /**
  225. *
  226. * @param stressTestRequest
  227. * @return
  228. * @throws NoSuchMethodException
  229. */
  230. protected Method getMethod(GwtRpcCommLayerPojoRequest stressTestRequest) throws NoSuchMethodException, ClassNotFoundException {
  231. int count = 0;
  232. Class<?> paramClasses[] = new Class[stressTestRequest.getMethodParameters().size()];
  233. LinkedList<Class<?>> lstParameterClasses = new LinkedList<Class<?>>();
  234. for (String methodName: stressTestRequest.getParameterClassNames()) {
  235. lstParameterClasses.add(Class.forName(methodName));
  236. }
  237. Class[] arrParameterClasses = lstParameterClasses.toArray(new Class[0]);
  238. return getClass().getMethod(stressTestRequest.getMethodName(), arrParameterClasses);
  239. }
  240. /**
  241. *
  242. * @param stressTestRequest
  243. * @param method
  244. * @return
  245. * @throws java.lang.reflect.InvocationTargetException
  246. * @throws IllegalAccessException
  247. */
  248. protected Object invokeMethod(GwtRpcCommLayerPojoRequest stressTestRequest, Method method) throws InvocationTargetException, IllegalAccessException
  249. {
  250. //todo: call toArray with correct size Object Array
  251. Object paramsAsObjects[] = stressTestRequest.getMethodParameters().toArray( new Object[0]);
  252. Object instance = method.invoke(servletInstance, paramsAsObjects);
  253. return instance;
  254. }
  255. }