]> source.dussan.org Git - vaadin-framework.git/commitdiff
Refactor RpcManager to provide info about parameter types (#8879)
authorLeif Åstrand <leif@vaadin.com>
Thu, 31 May 2012 13:31:26 +0000 (16:31 +0300)
committerLeif Åstrand <leif@vaadin.com>
Wed, 6 Jun 2012 10:33:42 +0000 (13:33 +0300)
This is an intermediate step towards decoding everything received from
the server based on its declared type.

src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml
src/com/vaadin/terminal/gwt/client/communication/GeneratedRpcMethodProvider.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/communication/RpcManager.java
src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/communication/Type.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/widgetsetutils/RpcManagerGenerator.java [deleted file]

index 74dc78d9b88baff16ecb16eb1f0c213788dc8afe..daa5e9f24d536271863ed203e51324e991fb585b 100644 (file)
@@ -63,9 +63,9 @@
 
        <!-- Generate client side RPC manager for server to client RPC -->
        <generate-with
-               class="com.vaadin.terminal.gwt.widgetsetutils.RpcManagerGenerator">
+               class="com.vaadin.terminal.gwt.widgetsetutils.GeneratedRpcMethodProviderGenerator">
                <when-type-assignable
-                       class="com.vaadin.terminal.gwt.client.communication.RpcManager" />
+                       class="com.vaadin.terminal.gwt.client.communication.GeneratedRpcMethodProvider" />
        </generate-with>
 
        <generate-with
diff --git a/src/com/vaadin/terminal/gwt/client/communication/GeneratedRpcMethodProvider.java b/src/com/vaadin/terminal/gwt/client/communication/GeneratedRpcMethodProvider.java
new file mode 100644 (file)
index 0000000..c924660
--- /dev/null
@@ -0,0 +1,20 @@
+/* 
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.communication;
+
+import java.util.Collection;
+
+/**
+ * Provides runtime data about client side RPC calls received from the server to
+ * the client-side code.
+ * 
+ * A GWT generator is used to create an implementation of this class at
+ * run-time.
+ * 
+ * @since 7.0
+ */
+public interface GeneratedRpcMethodProvider {
+
+    public Collection<RpcMethod> getGeneratedRpcMethods();
+}
index 302e6eaa55db46763da2837bc00cdf451ca6ef61..1d3447687d5a3ed1c1bba60d2a1272f8ff557f19 100644 (file)
@@ -4,9 +4,13 @@
 
 package com.vaadin.terminal.gwt.client.communication;
 
-import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 
+import com.google.gwt.core.client.GWT;
 import com.vaadin.terminal.gwt.client.ConnectorMap;
+import com.vaadin.terminal.gwt.client.ServerConnector;
 
 /**
  * Client side RPC manager that can invoke methods based on RPC calls received
@@ -17,7 +21,21 @@ import com.vaadin.terminal.gwt.client.ConnectorMap;
  * 
  * @since 7.0
  */
-public interface RpcManager extends Serializable {
+public class RpcManager {
+
+    private final Map<String, RpcMethod> methodMap = new HashMap<String, RpcMethod>();
+
+    public RpcManager() {
+        GeneratedRpcMethodProvider provider = GWT
+                .create(GeneratedRpcMethodProvider.class);
+        Collection<RpcMethod> methods = provider.getGeneratedRpcMethods();
+        for (RpcMethod rpcMethod : methods) {
+            methodMap.put(
+                    rpcMethod.getInterfaceName() + "."
+                            + rpcMethod.getMethodName(), rpcMethod);
+        }
+    }
+
     /**
      * Perform server to client RPC invocation.
      * 
@@ -28,5 +46,40 @@ public interface RpcManager extends Serializable {
      *            connectors referenced in parameters
      */
     public void applyInvocation(MethodInvocation invocation,
-            ConnectorMap connectorMap);
+            ConnectorMap connectorMap) {
+        ServerConnector connector = connectorMap.getConnector(invocation
+                .getConnectorId());
+        String signature = getSignature(invocation);
+        if (connector == null) {
+            throw new IllegalStateException("Target connector ("
+                    + invocation.getConnectorId() + ") not found for RCC to "
+                    + signature);
+        }
+
+        RpcMethod rpcMethod = getRpcMethod(signature);
+        Collection<ClientRpc> implementations = connector
+                .getRpcImplementations(invocation.getInterfaceName());
+        for (ClientRpc clientRpc : implementations) {
+            rpcMethod.applyInvocation(clientRpc, invocation.getParameters());
+        }
+    }
+
+    private RpcMethod getRpcMethod(String signature) {
+        RpcMethod rpcMethod = methodMap.get(signature);
+        if (rpcMethod == null) {
+            throw new IllegalStateException("There is no information about "
+                    + signature
+                    + ". Did you remember to compile the right widgetset?");
+        }
+        return rpcMethod;
+    }
+
+    private static String getSignature(MethodInvocation invocation) {
+        return invocation.getInterfaceName() + "." + invocation.getMethodName();
+    }
+
+    public Type[] getParameterTypes(MethodInvocation invocation) {
+        return getRpcMethod(getSignature(invocation)).getParameterTypes();
+    }
+
 }
diff --git a/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java b/src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java
new file mode 100644 (file)
index 0000000..abdcf73
--- /dev/null
@@ -0,0 +1,32 @@
+/* 
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.communication;
+
+public abstract class RpcMethod {
+    private String interfaceName;
+    private String methodName;
+    private Type[] parameterTypes;
+
+    public RpcMethod(String interfaceName, String methodName,
+            Type... parameterTypes) {
+        this.interfaceName = interfaceName;
+        this.methodName = methodName;
+        this.parameterTypes = parameterTypes;
+    }
+
+    public String getInterfaceName() {
+        return interfaceName;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public Type[] getParameterTypes() {
+        return parameterTypes;
+    }
+
+    public abstract void applyInvocation(ClientRpc target, Object... parameters);
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/communication/Type.java b/src/com/vaadin/terminal/gwt/client/communication/Type.java
new file mode 100644 (file)
index 0000000..dc33f76
--- /dev/null
@@ -0,0 +1,40 @@
+/* 
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.communication;
+
+public class Type {
+    private final String baseTypeName;
+    private final Type[] parameterTypes;
+
+    public Type(String baseTypeName, Type[] parameterTypes) {
+        this.baseTypeName = baseTypeName;
+        this.parameterTypes = parameterTypes;
+    }
+
+    public String getBaseTypeName() {
+        return baseTypeName;
+    }
+
+    public Type[] getParameterTypes() {
+        return parameterTypes;
+    }
+
+    @Override
+    public String toString() {
+        String string = baseTypeName;
+        if (parameterTypes != null) {
+            string += '<';
+            for (int i = 0; i < parameterTypes.length; i++) {
+                if (i != 0) {
+                    string += ',';
+                }
+                string += parameterTypes[i].toString();
+            }
+            string += '>';
+        }
+
+        return string;
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java
new file mode 100644 (file)
index 0000000..f0db488
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.widgetsetutils;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.google.gwt.core.ext.Generator;
+import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.core.ext.typeinfo.JParameterizedType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
+import com.google.gwt.user.rebind.SourceWriter;
+import com.vaadin.terminal.gwt.client.communication.ClientRpc;
+import com.vaadin.terminal.gwt.client.communication.GeneratedRpcMethodProvider;
+import com.vaadin.terminal.gwt.client.communication.RpcManager;
+import com.vaadin.terminal.gwt.client.communication.RpcMethod;
+
+/**
+ * GWT generator that creates an implementation for {@link RpcManager} on the
+ * client side classes for executing RPC calls received from the the server.
+ * 
+ * @since 7.0
+ */
+public class GeneratedRpcMethodProviderGenerator extends Generator {
+
+    @Override
+    public String generate(TreeLogger logger, GeneratorContext context,
+            String typeName) throws UnableToCompleteException {
+
+        String packageName = null;
+        String className = null;
+        try {
+            TypeOracle typeOracle = context.getTypeOracle();
+
+            // get classType and save instance variables
+            JClassType classType = typeOracle.getType(typeName);
+            packageName = classType.getPackage().getName();
+            className = classType.getSimpleSourceName() + "Impl";
+            // Generate class source code for SerializerMapImpl
+            generateClass(logger, context, packageName, className);
+        } catch (Exception e) {
+            logger.log(TreeLogger.ERROR,
+                    "SerializerMapGenerator creation failed", e);
+        }
+        // return the fully qualifed name of the class generated
+        return packageName + "." + className;
+    }
+
+    /**
+     * Generate source code for RpcManagerImpl
+     * 
+     * @param logger
+     *            Logger object
+     * @param context
+     *            Generator context
+     * @param packageName
+     *            package name for the class to generate
+     * @param className
+     *            class name for the class to generate
+     */
+    private void generateClass(TreeLogger logger, GeneratorContext context,
+            String packageName, String className) {
+        // get print writer that receives the source code
+        PrintWriter printWriter = null;
+        printWriter = context.tryCreate(logger, packageName, className);
+        // print writer if null, source code has ALREADY been generated
+        if (printWriter == null) {
+            return;
+        }
+        logger.log(Type.INFO,
+                "Detecting server to client RPC interface types...");
+        Date date = new Date();
+        TypeOracle typeOracle = context.getTypeOracle();
+        JClassType serverToClientRpcType = typeOracle.findType(ClientRpc.class
+                .getName());
+        JClassType[] rpcInterfaceSubtypes = serverToClientRpcType.getSubtypes();
+
+        // init composer, set class properties, create source writer
+        ClassSourceFileComposerFactory composer = null;
+        composer = new ClassSourceFileComposerFactory(packageName, className);
+        composer.addImport("com.google.gwt.core.client.GWT");
+        composer.addImport(RpcMethod.class.getName());
+        composer.addImport(ClientRpc.class.getName());
+        composer.addImport(com.vaadin.terminal.gwt.client.communication.Type.class
+                .getName());
+        composer.addImplementedInterface(GeneratedRpcMethodProvider.class
+                .getName());
+        SourceWriter sourceWriter = composer.createSourceWriter(context,
+                printWriter);
+        sourceWriter.indent();
+
+        List<JMethod> rpcMethods = new ArrayList<JMethod>();
+
+        sourceWriter
+                .println("public java.util.Collection<RpcMethod> getGeneratedRpcMethods() {");
+        sourceWriter.indent();
+
+        sourceWriter
+                .println("java.util.ArrayList<RpcMethod> list = new java.util.ArrayList<RpcMethod>();");
+
+        // iterate over RPC interfaces and create helper methods for each
+        // interface
+        for (JClassType type : rpcInterfaceSubtypes) {
+            if (null == type.isInterface()) {
+                // only interested in interfaces here, not implementations
+                continue;
+            }
+
+            // loop over the methods of the interface and its superinterfaces
+            // methods
+            for (JClassType currentType : type.getFlattenedSupertypeHierarchy()) {
+                for (JMethod method : currentType.getMethods()) {
+
+                    // RpcMethod(String interfaceName, String methodName,
+                    // Type... parameterTypes)
+                    sourceWriter.print("list.add(new RpcMethod(\""
+                            + type.getQualifiedSourceName() + "\", \""
+                            + method.getName() + "\"");
+                    JType[] parameterTypes = method.getParameterTypes();
+                    for (JType parameter : parameterTypes) {
+                        sourceWriter.print(", ");
+                        writeTypeCreator(sourceWriter, parameter);
+                    }
+                    sourceWriter.println(") {");
+                    sourceWriter.indent();
+
+                    sourceWriter
+                            .println("public void applyInvocation(ClientRpc target, Object... parameters) {");
+                    sourceWriter.indent();
+
+                    sourceWriter.print("((" + type.getQualifiedSourceName()
+                            + ")target)." + method.getName() + "(");
+                    for (int i = 0; i < parameterTypes.length; i++) {
+                        JType parameterType = parameterTypes[i];
+                        if (i != 0) {
+                            sourceWriter.print(", ");
+                        }
+                        sourceWriter.print("("
+                                + parameterType.getQualifiedSourceName()
+                                + ") parameters[" + i + "]");
+                    }
+                    sourceWriter.println(");");
+
+                    sourceWriter.outdent();
+                    sourceWriter.println("}");
+
+                    sourceWriter.outdent();
+                    sourceWriter.println("});");
+                }
+            }
+        }
+
+        sourceWriter.println("return list;");
+
+        sourceWriter.outdent();
+        sourceWriter.println("}");
+        sourceWriter.println();
+
+        // close generated class
+        sourceWriter.outdent();
+        sourceWriter.println("}");
+        // commit generated class
+        context.commit(logger, printWriter);
+        logger.log(Type.INFO,
+                "Done. (" + (new Date().getTime() - date.getTime()) / 1000
+                        + "seconds)");
+
+    }
+
+    private void writeTypeCreator(SourceWriter sourceWriter, JType type) {
+        sourceWriter.print("new Type(\""
+                + type.getErasedType().getQualifiedSourceName() + "\", ");
+        JParameterizedType parameterized = type.isParameterized();
+        if (parameterized != null) {
+            sourceWriter.print("new Type[] {");
+            JClassType[] typeArgs = parameterized.getTypeArgs();
+            for (JClassType jClassType : typeArgs) {
+                writeTypeCreator(sourceWriter, jClassType);
+                sourceWriter.print(", ");
+            }
+            sourceWriter.print("}");
+        } else {
+            sourceWriter.print("null");
+        }
+        sourceWriter.print(")");
+    }
+
+    private String getInvokeMethodName(JClassType type) {
+        return "invoke" + type.getQualifiedSourceName().replaceAll("\\.", "_");
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/RpcManagerGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/RpcManagerGenerator.java
deleted file mode 100644 (file)
index 2899061..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.widgetsetutils;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import com.google.gwt.core.ext.Generator;
-import com.google.gwt.core.ext.GeneratorContext;
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.TreeLogger.Type;
-import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.typeinfo.JClassType;
-import com.google.gwt.core.ext.typeinfo.JMethod;
-import com.google.gwt.core.ext.typeinfo.JType;
-import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
-import com.google.gwt.user.rebind.SourceWriter;
-import com.vaadin.terminal.gwt.client.ServerConnector;
-import com.vaadin.terminal.gwt.client.ConnectorMap;
-import com.vaadin.terminal.gwt.client.communication.ClientRpc;
-import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
-import com.vaadin.terminal.gwt.client.communication.RpcManager;
-
-/**
- * GWT generator that creates an implementation for {@link RpcManager} on the
- * client side classes for executing RPC calls received from the the server.
- * 
- * @since 7.0
- */
-public class RpcManagerGenerator extends Generator {
-
-    @Override
-    public String generate(TreeLogger logger, GeneratorContext context,
-            String typeName) throws UnableToCompleteException {
-
-        String packageName = null;
-        String className = null;
-        try {
-            TypeOracle typeOracle = context.getTypeOracle();
-
-            // get classType and save instance variables
-            JClassType classType = typeOracle.getType(typeName);
-            packageName = classType.getPackage().getName();
-            className = classType.getSimpleSourceName() + "Impl";
-            // Generate class source code for SerializerMapImpl
-            generateClass(logger, context, packageName, className);
-        } catch (Exception e) {
-            logger.log(TreeLogger.ERROR,
-                    "SerializerMapGenerator creation failed", e);
-        }
-        // return the fully qualifed name of the class generated
-        return packageName + "." + className;
-    }
-
-    /**
-     * Generate source code for RpcManagerImpl
-     * 
-     * @param logger
-     *            Logger object
-     * @param context
-     *            Generator context
-     * @param packageName
-     *            package name for the class to generate
-     * @param className
-     *            class name for the class to generate
-     */
-    private void generateClass(TreeLogger logger, GeneratorContext context,
-            String packageName, String className) {
-        // get print writer that receives the source code
-        PrintWriter printWriter = null;
-        printWriter = context.tryCreate(logger, packageName, className);
-        // print writer if null, source code has ALREADY been generated
-        if (printWriter == null) {
-            return;
-        }
-        logger.log(Type.INFO,
-                "Detecting server to client RPC interface types...");
-        Date date = new Date();
-        TypeOracle typeOracle = context.getTypeOracle();
-        JClassType serverToClientRpcType = typeOracle.findType(ClientRpc.class
-                .getName());
-        JClassType[] rpcInterfaceSubtypes = serverToClientRpcType.getSubtypes();
-
-        // init composer, set class properties, create source writer
-        ClassSourceFileComposerFactory composer = null;
-        composer = new ClassSourceFileComposerFactory(packageName, className);
-        composer.addImport("com.google.gwt.core.client.GWT");
-        composer.addImplementedInterface(RpcManager.class.getName());
-        SourceWriter sourceWriter = composer.createSourceWriter(context,
-                printWriter);
-        sourceWriter.indent();
-
-        List<JClassType> rpcInterfaces = new ArrayList<JClassType>();
-
-        // iterate over RPC interfaces and create helper methods for each
-        // interface
-        for (JClassType type : rpcInterfaceSubtypes) {
-            if (null == type.isInterface()) {
-                // only interested in interfaces here, not implementations
-                continue;
-            }
-            rpcInterfaces.add(type);
-            // generate method to call methods of an RPC interface
-            sourceWriter.println("private void " + getInvokeMethodName(type)
-                    + "(" + MethodInvocation.class.getName() + " invocation, "
-                    + ConnectorMap.class.getName() + " connectorMap) {");
-            sourceWriter.indent();
-
-            // loop over the methods of the interface and its superinterfaces
-            // methods
-            for (JClassType currentType : type.getFlattenedSupertypeHierarchy()) {
-                for (JMethod method : currentType.getMethods()) {
-                    sourceWriter.println("if (\"" + method.getName()
-                            + "\".equals(invocation.getMethodName())) {");
-                    sourceWriter.indent();
-                    // construct parameter string with appropriate casts
-                    String paramString = "";
-                    JType[] parameterTypes = method.getParameterTypes();
-                    for (int i = 0; i < parameterTypes.length; ++i) {
-                        paramString = paramString + "("
-                                + parameterTypes[i].getQualifiedSourceName()
-                                + ") invocation.getParameters()[" + i + "]";
-                        if (i < parameterTypes.length - 1) {
-                            paramString = paramString + ", ";
-                        }
-                    }
-                    sourceWriter
-                            .println(ServerConnector.class.getName()
-                                    + " connector = connectorMap.getConnector(invocation.getConnectorId());");
-                    sourceWriter
-                            .println("for ("
-                                    + ClientRpc.class.getName()
-                                    + " rpcImplementation : connector.getRpcImplementations(\""
-                                    + type.getQualifiedSourceName() + "\")) {");
-                    sourceWriter.indent();
-                    sourceWriter.println("((" + type.getQualifiedSourceName()
-                            + ") rpcImplementation)." + method.getName() + "("
-                            + paramString + ");");
-                    sourceWriter.outdent();
-                    sourceWriter.println("}");
-                    sourceWriter.println("return;");
-                    sourceWriter.outdent();
-                    sourceWriter.println("}");
-                }
-            }
-
-            sourceWriter.outdent();
-            sourceWriter.println("}");
-
-            logger.log(Type.DEBUG,
-                    "Constructed helper method for server to client RPC for "
-                            + type.getName());
-        }
-
-        // generate top-level "switch-case" method to select the correct
-        // previously generated method based on the RPC interface
-        sourceWriter.println("public void applyInvocation("
-                + MethodInvocation.class.getName() + " invocation, "
-                + ConnectorMap.class.getName() + " connectorMap) {");
-        sourceWriter.indent();
-
-        for (JClassType type : rpcInterfaces) {
-            sourceWriter.println("if (\"" + type.getQualifiedSourceName()
-                    + "\".equals(invocation.getInterfaceName())) {");
-            sourceWriter.indent();
-            sourceWriter.println(getInvokeMethodName(type)
-                    + "(invocation, connectorMap);");
-            sourceWriter.println("return;");
-            sourceWriter.outdent();
-            sourceWriter.println("}");
-
-            logger.log(Type.INFO,
-                    "Configured server to client RPC for " + type.getName());
-        }
-        sourceWriter.outdent();
-        sourceWriter.println("}");
-
-        // close generated class
-        sourceWriter.outdent();
-        sourceWriter.println("}");
-        // commit generated class
-        context.commit(logger, printWriter);
-        logger.log(Type.INFO,
-                "Done. (" + (new Date().getTime() - date.getTime()) / 1000
-                        + "seconds)");
-
-    }
-
-    private String getInvokeMethodName(JClassType type) {
-        return "invoke" + type.getQualifiedSourceName().replaceAll("\\.", "_");
-    }
-}