From: Henri Sara Date: Wed, 25 Jan 2012 10:34:43 +0000 (+0200) Subject: Register and use multiple RPC implementations by RPC interface (#8278). X-Git-Tag: 7.0.0.alpha2~440^2~33 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=03781335fc409ac9a8e3d480bed033d0b14bc844;p=vaadin-framework.git Register and use multiple RPC implementations by RPC interface (#8278). --- diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index f5f735d184..5e1bb89b0c 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -77,6 +77,7 @@ public class ApplicationConnection { private static final String ERROR_CLASSNAME_EXT = "-error"; + public static final String UPDATE_VARIABLE_INTERFACE = "v"; public static final String UPDATE_VARIABLE_METHOD = "v"; public static final char VAR_BURST_SEPARATOR = '\u001d'; @@ -1108,8 +1109,8 @@ public class ApplicationConnection { // note that type is now deduced from value // TODO could eliminate invocations of same shared variable setter addMethodInvocationToQueue(new MethodInvocation(paintableId, - UPDATE_VARIABLE_METHOD, new Object[] { variableName, value }), - immediate); + UPDATE_VARIABLE_INTERFACE, UPDATE_VARIABLE_METHOD, + new Object[] { variableName, value }), immediate); } /** @@ -1201,6 +1202,8 @@ public class ApplicationConnection { invocationJson.set(0, new JSONString(invocation.getPaintableId())); invocationJson.set(1, + new JSONString(invocation.getInterfaceName())); + invocationJson.set(2, new JSONString(invocation.getMethodName())); JSONArray paramJson = new JSONArray(); for (int i = 0; i < invocation.getParameters().length; ++i) { @@ -1208,7 +1211,7 @@ public class ApplicationConnection { paramJson.set(i, JsonEncoder.encode( invocation.getParameters()[i], getPaintableMap())); } - invocationJson.set(2, paramJson); + invocationJson.set(3, paramJson); reqJson.set(reqJson.size(), invocationJson); } diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java index a3cf20ae28..9cc155c2bd 100644 --- a/src/com/vaadin/terminal/gwt/client/Util.java +++ b/src/com/vaadin/terminal/gwt/client/Util.java @@ -963,8 +963,9 @@ public class Util { formattedParams = (null != parameters) ? parameters .toString() : null; } - VConsole.log("\t\t" + invocation.getMethodName() + "(" - + formattedParams + ")"); + VConsole.log("\t\t" + invocation.getInterfaceName() + "." + + invocation.getMethodName() + "(" + formattedParams + + ")"); } } } diff --git a/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java b/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java index 5fe1846b34..33ea3fb5c2 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java +++ b/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java @@ -9,12 +9,14 @@ package com.vaadin.terminal.gwt.client.communication; public class MethodInvocation { private final String paintableId; + private final String interfaceName; private final String methodName; private final Object[] parameters; - public MethodInvocation(String paintableId, String methodName, - Object[] parameters) { + public MethodInvocation(String paintableId, String interfaceName, + String methodName, Object[] parameters) { this.paintableId = paintableId; + this.interfaceName = interfaceName; this.methodName = methodName; this.parameters = parameters; } @@ -23,6 +25,10 @@ public class MethodInvocation { return paintableId; } + public String getInterfaceName() { + return interfaceName; + } + public String getMethodName() { return methodName; } diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index 6ca5600d1d..8addc8fbff 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -1242,10 +1242,10 @@ public abstract class AbstractCommunicationManager implements nextInvocation = invocations.get(i + 1); } - final String methodName = invocation.getMethodName(); + final String interfaceName = invocation.getInterfaceName(); - if (!ApplicationConnection.UPDATE_VARIABLE_METHOD - .equals(methodName)) { + if (!ApplicationConnection.UPDATE_VARIABLE_INTERFACE + .equals(interfaceName)) { // handle other RPC calls than variable changes applyInvocation(invocation); continue; @@ -1369,15 +1369,16 @@ public abstract class AbstractCommunicationManager implements for (int i = 0; i < invocationsJson.length(); ++i) { JSONArray invocationJson = invocationsJson.getJSONArray(i); String paintableId = invocationJson.getString(0); - String methodName = invocationJson.getString(1); - JSONArray parametersJson = invocationJson.getJSONArray(2); + String interfaceName = invocationJson.getString(1); + String methodName = invocationJson.getString(2); + JSONArray parametersJson = invocationJson.getJSONArray(3); Object[] parameters = new Object[parametersJson.length()]; for (int j = 0; j < parametersJson.length(); ++j) { parameters[j] = JsonDecoder.convertVariableValue( parametersJson.getJSONArray(j), this); } MethodInvocation invocation = new MethodInvocation(paintableId, - methodName, parameters); + interfaceName, methodName, parameters); invocations.add(invocation); } return invocations; diff --git a/src/com/vaadin/terminal/gwt/server/RpcTarget.java b/src/com/vaadin/terminal/gwt/server/RpcTarget.java index a5dbd7ce11..8a2258b083 100644 --- a/src/com/vaadin/terminal/gwt/server/RpcTarget.java +++ b/src/com/vaadin/terminal/gwt/server/RpcTarget.java @@ -10,5 +10,13 @@ import com.vaadin.terminal.VariableOwner; * @since 7.0 */ public interface RpcTarget { - public RpcManager getRpcManager(); + /** + * Returns the RPC manager instance to use when receiving calls for an RPC + * interface. + * + * @param rpcInterface + * interface for which the call was made + * @return RpcManager or null if none found for the interface + */ + public RpcManager getRpcManager(Class rpcInterface); } diff --git a/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java b/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java index 0c8a6d1735..2a824704c5 100644 --- a/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java +++ b/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java @@ -18,10 +18,11 @@ import com.vaadin.terminal.gwt.client.communication.MethodInvocation; * * @since 7.0 */ -public class ServerRpcManager implements RpcManager { +public class ServerRpcManager implements RpcManager { private final RpcTarget target; - private final Object implementation; + private final T implementation; + private final Class rpcInterface; private static final Map invocationMethodCache = new ConcurrentHashMap( 128, 0.75f, 1); @@ -49,10 +50,14 @@ public class ServerRpcManager implements RpcManager { * RPC call target (normally a {@link Paintable}) * @param implementation * RPC interface implementation for the target + * @param rpcInterface + * RPC interface type */ - public ServerRpcManager(RpcTarget target, Object implementation) { + public ServerRpcManager(RpcTarget target, T implementation, + Class rpcInterface) { this.target = target; this.implementation = implementation; + this.rpcInterface = rpcInterface; } /** @@ -66,12 +71,21 @@ public class ServerRpcManager implements RpcManager { */ public static void applyInvocation(RpcTarget target, MethodInvocation invocation) { - RpcManager manager = target.getRpcManager(); - if (manager != null) { - manager.applyInvocation(invocation); - } else { + try { + Class rpcInterfaceClass = Class.forName(invocation + .getInterfaceName()); + RpcManager manager = target.getRpcManager(rpcInterfaceClass); + if (manager != null) { + manager.applyInvocation(invocation); + } else { + throw new RuntimeException( + "RPC call to a target without an RPC manager."); + } + } catch (ClassNotFoundException e) { throw new RuntimeException( - "RPC call to a target without an RPC manager."); + "No RPC manager registered for RPC interface " + + invocation.getInterfaceName() + " of the target " + + target + "."); } } @@ -89,10 +103,19 @@ public class ServerRpcManager implements RpcManager { * * @return RPC interface implementation */ - protected Object getImplementation() { + protected T getImplementation() { return implementation; } + /** + * Returns the RPC interface type managed by this RPC manager instance. + * + * @return RPC interface type + */ + protected Class getRpcInterface() { + return rpcInterface; + } + /** * Invoke a method in a server side RPC target class. This method is to be * used by the RPC framework and unit testing tools only. @@ -102,13 +125,15 @@ public class ServerRpcManager implements RpcManager { */ public void applyInvocation(MethodInvocation invocation) { String methodName = invocation.getMethodName(); + // here, we already know that the interface is an rpcInterface Object[] arguments = invocation.getParameters(); - Method method = findInvocationMethod(implementation.getClass(), - methodName, arguments.length); + Method method = findInvocationMethod(rpcInterface, methodName, + arguments.length); if (method == null) { throw new RuntimeException(implementation + " does not contain " - + methodName + " with " + arguments.length + " parameters"); + + rpcInterface.getName() + "." + methodName + " with " + + arguments.length + " parameters"); } Class[] parameterTypes = method.getParameterTypes(); @@ -128,8 +153,8 @@ public class ServerRpcManager implements RpcManager { } } - private static Method findInvocationMethod(Class targetType, - String methodName, int parameterCount) { + private Method findInvocationMethod(Class targetType, String methodName, + int parameterCount) { // TODO currently only using method name and number of parameters as the // signature String signature = targetType.getName() + "." + methodName + "(" @@ -148,17 +173,14 @@ public class ServerRpcManager implements RpcManager { return invocationMethod; } - private static Method doFindInvocationMethod(Class targetType, + private Method doFindInvocationMethod(Class targetType, String methodName, int parameterCount) { - Class[] interfaces = targetType.getInterfaces(); - for (Class iface : interfaces) { - Method[] methods = iface.getMethods(); - for (Method method : methods) { - Class[] parameterTypes = method.getParameterTypes(); - if (method.getName().equals(methodName) - && parameterTypes.length == parameterCount) { - return method; - } + Method[] methods = targetType.getMethods(); + for (Method method : methods) { + Class[] parameterTypes = method.getParameterTypes(); + if (method.getName().equals(methodName) + && parameterTypes.length == parameterCount) { + return method; } } return null; diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java index e00b558af0..31aff7a94f 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java @@ -55,7 +55,6 @@ public class RpcProxyGenerator extends Generator { ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory( requestedType.getPackage().getName(), generatedClassName); - // composer.setSuperclass(requestedType.getQualifiedSourceName()); composer.addImplementedInterface(requestedType.getQualifiedSourceName()); composer.addImplementedInterface(initializableInterface .getQualifiedSourceName()); @@ -77,8 +76,8 @@ public class RpcProxyGenerator extends Generator { writeCommonFieldsAndMethods(logger, writer, typeOracle); // actual proxy methods forwarding calls to the server - writeRemoteProxyMethods(logger, writer, typeOracle, requestedType - .isClassOrInterface().getMethods()); + writeRemoteProxyMethods(logger, writer, typeOracle, requestedType, + requestedType.isClassOrInterface().getMethods()); // End of class writer.outdent(); @@ -115,14 +114,16 @@ public class RpcProxyGenerator extends Generator { } private static void writeRemoteProxyMethods(TreeLogger logger, - SourceWriter writer, TypeOracle typeOracle, JMethod[] methods) { + SourceWriter writer, TypeOracle typeOracle, + JClassType requestedType, JMethod[] methods) { for (JMethod m : methods) { writer.print(m.getReadableDeclaration(false, false, false, false, true)); writer.println(" {"); writer.indent(); - writer.print("client.addMethodInvocationToQueue(new MethodInvocation(paintableId, \""); + writer.print("client.addMethodInvocationToQueue(new MethodInvocation(paintableId, \"" + + requestedType.getQualifiedBinaryName() + "\", \""); writer.print(m.getName()); writer.print("\", new Object[] {"); // new Object[] { ... } for parameters - autoboxing etc. by the diff --git a/src/com/vaadin/ui/AbstractComponent.java b/src/com/vaadin/ui/AbstractComponent.java index a5f2fa9601..de114e996e 100644 --- a/src/com/vaadin/ui/AbstractComponent.java +++ b/src/com/vaadin/ui/AbstractComponent.java @@ -9,6 +9,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; @@ -157,9 +158,10 @@ public abstract class AbstractComponent implements Component, MethodEventSource private ActionManager actionManager; /** - * RPC call manager that handles incoming RPC calls. + * A map from RPC interface class to the RPC call manager that handles + * incoming RPC calls for that interface. */ - private RpcManager rpcManager = null; + private Map, RpcManager> rpcManagerMap = new HashMap, RpcManager>(); /* Constructor */ @@ -1538,27 +1540,32 @@ public abstract class AbstractComponent implements Component, MethodEventSource } /** - * Sets the RPC interface implementation for this component. + * Registers an RPC interface implementation for this component. * - * A component should have exactly one RPC interface and its implementation - * to be able to receive RPC calls. + * A component can listen to multiple RPC interfaces, and subclasses can + * register additional implementations. * * @since 7.0 * * @param implementation * RPC interface implementation + * @param rpcInterfaceType + * RPC interface class for which the implementation should be + * registered */ - protected void setRpcImplementation(Object implementation) { + protected void registerRpcImplementation(T implementation, + Class rpcInterfaceType) { if (this instanceof RpcTarget) { - rpcManager = new ServerRpcManager((RpcTarget) this, implementation); + rpcManagerMap.put(rpcInterfaceType, new ServerRpcManager( + (RpcTarget) this, implementation, rpcInterfaceType)); } else { throw new RuntimeException( "Cannot register an RPC implementation for a component that is not an RpcTarget"); } } - public RpcManager getRpcManager() { - return rpcManager; + public RpcManager getRpcManager(Class rpcInterface) { + return rpcManagerMap.get(rpcInterface); } }