package com.googlecode.gwt.test.rpc; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.StatusCodeException; import com.googlecode.gwt.test.RemoteServiceExecutionHandler; import com.googlecode.gwt.test.exceptions.GwtTestException; import com.googlecode.gwt.test.exceptions.GwtTestRpcException; import com.googlecode.gwt.test.internal.BrowserSimulatorImpl; import com.googlecode.gwt.test.internal.GwtConfig; import com.googlecode.gwt.test.internal.patchers.AbstractRemoteServiceServletPatcher; import com.googlecode.gwt.test.utils.GwtReflectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; class GwtRpcInvocationHandler implements InvocationHandler { private static final Logger logger = LoggerFactory.getLogger(GwtRpcInvocationHandler.class); private final GwtRpcExceptionHandler exceptionHandler; private final Map<Method, Method> methodTable; private final GwtRpcSerializerHandler serializerHander; private final Object target; public GwtRpcInvocationHandler(Class<?> asyncClazz, Object target, GwtRpcExceptionHandler exceptionHandler, GwtRpcSerializerHandler serializerHandler) { this.target = target; this.exceptionHandler = exceptionHandler; this.serializerHander = serializerHandler; this.methodTable = new HashMap<Method, Method>(); for (Method m : asyncClazz.getMethods()) { for (Method m2 : target.getClass().getMethods()) { if (m.getName().equals(m2.getName()) && m.getParameterTypes().length == m2.getParameterTypes().length + 1) { methodTable.put(m, m2); GwtReflectionUtils.makeAccessible(m2); } } } } @SuppressWarnings("unchecked") public Object invoke(Object proxy, Method method, Object[] args) { Object[] subArgs = new Object[args.length - 1]; for (int i = 0; i < args.length - 1; i++) { subArgs[i] = args[i]; } final AsyncCallback<Object> callback = (AsyncCallback<Object>) args[args.length - 1]; final Method m = methodTable.get(method); Command asyncCallbackCommand; if (m == null) { logger.error("Method not found " + method); // error 500 async call asyncCallbackCommand = new Command() { public void execute() { callback.onFailure(new StatusCodeException(500, "No method found")); } }; } else { try { logger.debug("Invoking " + m + " on " + target.getClass().getName()); List<RemoteServiceExecutionHandler> handlers = GwtConfig.get().getModuleRunner().getRemoteServiceExecutionHandlers(); // notify for (RemoteServiceExecutionHandler handler : handlers) { handler.beforeRpcRequestSerialization(m, subArgs); } // Serialize objects Object[] serializedArgs = new Object[subArgs.length]; for (int i = 0; i < subArgs.length; i++) { try { serializedArgs[i] = serializerHander.serializeUnserialize(subArgs[i]); } catch (Exception e) { throw new GwtTestRpcException("Error while serializing argument " + i + " of type " + subArgs[i].getClass().getName() + " in method " + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "(..)", e); } } // notify for (RemoteServiceExecutionHandler handler : handlers) { handler.beforeRpcRequestSerialization(m, serializedArgs); } AbstractRemoteServiceServletPatcher.currentCalledMethod = m; // notify for (RemoteServiceExecutionHandler handler : handlers) { handler.beforeRpcMethodExecution(m, serializedArgs); } Object resultObject = m.invoke(target, serializedArgs); // notify for (RemoteServiceExecutionHandler handler : handlers) { handler.afterRpcMethodExecution(m, resultObject); } Object returnObject; try { // notify for (RemoteServiceExecutionHandler handler : handlers) { handler.beforeRpcResponseSerialization(m, resultObject); } returnObject = serializerHander.serializeUnserialize(resultObject); // notify for (RemoteServiceExecutionHandler handler : handlers) { handler.afterRpcResponseSerialization(m, returnObject); } } catch (Exception e) { throw new GwtTestRpcException("Error while serializing object of type " + resultObject.getClass().getName() + " which was returned from RPC Service " + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "(..)", e); } final Object o = returnObject; // success async call asyncCallbackCommand = new Command() { public void execute() { logger.debug("Result of " + m.getName() + " : " + o); callback.onSuccess(o); } }; } catch (final InvocationTargetException e) { if (GwtTestException.class.isInstance(e.getCause())) { throw (GwtTestException) e.getCause(); } asyncCallbackCommand = new Command() { public void execute() { logger.info("Exception when invoking service throw to handler " + e.getMessage()); exceptionHandler.handle(e.getCause(), callback); } }; } catch (final IllegalAccessException e) { asyncCallbackCommand = new Command() { public void execute() { logger.error("GWT RPC exception : " + e.toString(), e); callback.onFailure(new StatusCodeException(500, e.toString())); } }; } catch (final IllegalArgumentException e) { asyncCallbackCommand = new Command() { public void execute() { logger.error("GWT RPC exception : " + e.toString(), e); callback.onFailure(new StatusCodeException(500, e.toString())); } }; } } // delegate the execution to the Browser simulator BrowserSimulatorImpl.get().recordAsyncCall(asyncCallbackCommand); // async callback always return void return null; } }