]> source.dussan.org Git - vaadin-framework.git/commitdiff
Register and use multiple RPC implementations by RPC interface (#8278).
authorHenri Sara <hesara@vaadin.com>
Wed, 25 Jan 2012 10:34:43 +0000 (12:34 +0200)
committerHenri Sara <hesara@vaadin.com>
Wed, 25 Jan 2012 12:08:07 +0000 (14:08 +0200)
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/client/Util.java
src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
src/com/vaadin/terminal/gwt/server/RpcTarget.java
src/com/vaadin/terminal/gwt/server/ServerRpcManager.java
src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java
src/com/vaadin/ui/AbstractComponent.java

index f5f735d184def39b7a63a5b6b14e4b394d0edd53..5e1bb89b0c086f301f9e491b2b7a0e320ba68f57 100644 (file)
@@ -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);
             }
 
index a3cf20ae285f9da8b28e9dd3f8a4d070dea0cc1e..9cc155c2bdb52b4aaf7d961b961db115fd24b789 100644 (file)
@@ -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
+                        + ")");
             }
         }
     }
index 5fe1846b345ff6f26fc042a44e5d6302ceeee4f7..33ea3fb5c2b3a1eb15a18ff5ad97b0039df8a8d6 100644 (file)
@@ -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;
     }
index 6ca5600d1df55fa1c156fb19b8fb6fd52e282b85..8addc8fbffa9048ca77cfb0f94f66b7afaa7dc79 100644 (file)
@@ -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;
index a5dbd7ce11180cdc88976180cf0c8d7f71ef3917..8a2258b0838db421cc917d084aef8397c7a156b2 100644 (file)
@@ -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);
 }
index 0c8a6d17357afc415c5977a7fe3a944dac00765f..2a824704c5afac434d65bd2f2184f0d2eba6b0be 100644 (file)
@@ -18,10 +18,11 @@ import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
  * 
  * @since 7.0
  */
-public class ServerRpcManager implements RpcManager {
+public class ServerRpcManager<T> implements RpcManager {
 
     private final RpcTarget target;
-    private final Object implementation;
+    private final T implementation;
+    private final Class<T> rpcInterface;
 
     private static final Map<String, Method> invocationMethodCache = new ConcurrentHashMap<String, Method>(
             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<T> 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<T> 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;
index e00b558af015b1d962f95335554b547524c73763..31aff7a94f86675d1fe17b0c863be1bc555a5338 100644 (file)
@@ -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
index a5f2fa9601df52999354af36e11d4113113e70d4..de114e996eed05afd131df579b7722d51fdd6f34 100644 (file)
@@ -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<Class<?>, RpcManager> rpcManagerMap = new HashMap<Class<?>, 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 <T> void registerRpcImplementation(T implementation,
+            Class<T> rpcInterfaceType) {
         if (this instanceof RpcTarget) {
-            rpcManager = new ServerRpcManager((RpcTarget) this, implementation);
+            rpcManagerMap.put(rpcInterfaceType, new ServerRpcManager<T>(
+                    (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);
     }
 
 }