PageRenderTime 24ms CodeModel.GetById 1ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

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