]> source.dussan.org Git - vaadin-framework.git/commitdiff
Use ConnectorBundle for ServerRpc handling (#9371)
authorLeif Åstrand <leif@vaadin.com>
Tue, 21 Aug 2012 13:51:33 +0000 (16:51 +0300)
committerLeif Åstrand <leif@vaadin.com>
Wed, 22 Aug 2012 16:25:32 +0000 (19:25 +0300)
15 files changed:
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyCreatorGenerator.java [deleted file]
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java [deleted file]
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ServerRpcVisitor.java [new file with mode: 0644]
client/src/com/vaadin/Vaadin.gwt.xml
client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
client/src/com/vaadin/terminal/gwt/client/communication/InitializableServerRpc.java [deleted file]
client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java
client/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java
client/src/com/vaadin/terminal/gwt/client/metadata/InvokationHandler.java [new file with mode: 0644]
client/src/com/vaadin/terminal/gwt/client/metadata/Method.java
client/src/com/vaadin/terminal/gwt/client/metadata/ProxyHandler.java [new file with mode: 0644]
client/src/com/vaadin/terminal/gwt/client/metadata/Type.java
client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java

index 8cb04d93700c313c6443f720e9f00c4105b3046f..9f830d4a8df4ccd888487ec6748b045e3a2d63eb 100644 (file)
@@ -28,17 +28,22 @@ import com.google.gwt.core.ext.typeinfo.NotFoundException;
 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.shared.annotations.Delayed;
 import com.vaadin.shared.communication.ClientRpc;
 import com.vaadin.shared.communication.ServerRpc;
 import com.vaadin.shared.ui.Connect;
 import com.vaadin.shared.ui.Connect.LoadStyle;
 import com.vaadin.terminal.gwt.client.ServerConnector;
 import com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader;
+import com.vaadin.terminal.gwt.client.metadata.InvokationHandler;
+import com.vaadin.terminal.gwt.client.metadata.ProxyHandler;
+import com.vaadin.terminal.gwt.client.metadata.TypeData;
 import com.vaadin.terminal.gwt.client.metadata.TypeDataBundle;
 import com.vaadin.terminal.gwt.client.metadata.TypeDataStore;
 import com.vaadin.terminal.gwt.widgetsetutils.metadata.ClientRpcVisitor;
 import com.vaadin.terminal.gwt.widgetsetutils.metadata.ConnectorBundle;
 import com.vaadin.terminal.gwt.widgetsetutils.metadata.ConnectorInitVisitor;
+import com.vaadin.terminal.gwt.widgetsetutils.metadata.ServerRpcVisitor;
 import com.vaadin.terminal.gwt.widgetsetutils.metadata.StateInitVisitor;
 import com.vaadin.terminal.gwt.widgetsetutils.metadata.TypeVisitor;
 import com.vaadin.terminal.gwt.widgetsetutils.metadata.WidgetInitVisitor;
@@ -166,6 +171,112 @@ public class ConnectorBundleLoaderFactory extends Generator {
         writeReturnTypes(w, bundle);
         writeInvokers(w, bundle);
         writeParamTypes(w, bundle);
+        writeProxys(w, bundle);
+        wirteDelayedInfo(w, bundle);
+    }
+
+    private void wirteDelayedInfo(SourceWriter w, ConnectorBundle bundle) {
+        Map<JClassType, Set<JMethod>> needsDelayedInfo = bundle
+                .getNeedsDelayedInfo();
+        Set<Entry<JClassType, Set<JMethod>>> entrySet = needsDelayedInfo
+                .entrySet();
+        for (Entry<JClassType, Set<JMethod>> entry : entrySet) {
+            JClassType type = entry.getKey();
+            Set<JMethod> methods = entry.getValue();
+            for (JMethod method : methods) {
+                Delayed annotation = method.getAnnotation(Delayed.class);
+                if (annotation != null) {
+                    w.print("store.setDelayed(");
+                    printClassLiteral(w, type);
+                    w.print(", \"");
+                    w.print(escape(method.getName()));
+                    w.println("\");");
+
+                    if (annotation.lastonly()) {
+                        w.print("store.setLastonly(");
+                        printClassLiteral(w, type);
+                        w.print(", \"");
+                        w.print(escape(method.getName()));
+                        w.println("\");");
+                    }
+                }
+            }
+        }
+    }
+
+    private void writeProxys(SourceWriter w, ConnectorBundle bundle) {
+        Set<JClassType> needsProxySupport = bundle.getNeedsProxySupport();
+        for (JClassType type : needsProxySupport) {
+            w.print("store.setProxyHandler(");
+            printClassLiteral(w, type);
+            w.print(", new ");
+            w.print(ProxyHandler.class.getCanonicalName());
+            w.println("() {");
+            w.indent();
+
+            w.println("public Object createProxy(final "
+                    + InvokationHandler.class.getName() + " handler) {");
+            w.indent();
+
+            w.print("return new ");
+            w.print(type.getQualifiedSourceName());
+            w.println("() {");
+            w.indent();
+
+            JMethod[] methods = type.getOverridableMethods();
+            for (JMethod method : methods) {
+                if (method.isAbstract()) {
+                    w.print("public ");
+                    w.print(method.getReturnType().getQualifiedSourceName());
+                    w.print(" ");
+                    w.print(method.getName());
+                    w.print("(");
+
+                    JType[] types = method.getParameterTypes();
+                    for (int i = 0; i < types.length; i++) {
+                        if (i != 0) {
+                            w.print(", ");
+                        }
+                        w.print(types[i].getQualifiedSourceName());
+                        w.print(" p");
+                        w.print(Integer.toString(i));
+                    }
+
+                    w.println(") {");
+                    w.indent();
+
+                    if (!method.getReturnType().getQualifiedSourceName()
+                            .equals("void")) {
+                        w.print("return ");
+                    }
+
+                    w.print("handler.invoke(this, ");
+                    w.print(TypeData.class.getCanonicalName());
+                    w.print(".getType(");
+                    printClassLiteral(w, type);
+                    w.print(").getMethod(\"");
+                    w.print(escape(method.getName()));
+                    w.print("\"), new Object [] {");
+                    for (int i = 0; i < types.length; i++) {
+                        w.print("p" + i + ", ");
+                    }
+                    w.println("});");
+
+                    w.outdent();
+                    w.println("}");
+                }
+            }
+
+            w.outdent();
+            w.println("};");
+
+            w.outdent();
+            w.println("}");
+
+            w.outdent();
+            w.println("});");
+
+        }
     }
 
     private void writeParamTypes(SourceWriter w, ConnectorBundle bundle) {
@@ -176,11 +287,11 @@ public class ConnectorBundleLoaderFactory extends Generator {
 
             Set<JMethod> methods = entry.getValue();
             for (JMethod method : methods) {
-                w.println("store.setParamTypes(");
+                w.print("store.setParamTypes(");
                 printClassLiteral(w, type);
                 w.print(", \"");
                 w.print(escape(method.getName()));
-                w.println("\", new Type[] {");
+                w.print("\", new Type[] {");
 
                 for (JType parameter : method.getParameterTypes()) {
                     ConnectorBundleLoaderFactory.writeTypeCreator(w, parameter);
@@ -272,7 +383,7 @@ public class ConnectorBundleLoaderFactory extends Generator {
         for (JClassType type : constructors) {
             w.print("store.setConstructor(");
             printClassLiteral(w, type);
-            w.print(", new Invoker() {");
+            w.println(", new Invoker() {");
             w.indent();
 
             w.println("public Object invoke(Object target, Object[] params) {");
@@ -380,7 +491,8 @@ public class ConnectorBundleLoaderFactory extends Generator {
             throws NotFoundException {
         List<TypeVisitor> visitors = Arrays.<TypeVisitor> asList(
                 new ConnectorInitVisitor(), new StateInitVisitor(),
-                new WidgetInitVisitor(), new ClientRpcVisitor());
+                new WidgetInitVisitor(), new ClientRpcVisitor(),
+                new ServerRpcVisitor());
         for (TypeVisitor typeVisitor : visitors) {
             typeVisitor.init(oracle);
         }
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyCreatorGenerator.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyCreatorGenerator.java
deleted file mode 100644 (file)
index eccc646..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2011 Vaadin Ltd.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.terminal.gwt.widgetsetutils;
-
-import java.io.PrintWriter;
-import java.util.Date;
-
-import com.google.gwt.core.client.GWT;
-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.TypeOracle;
-import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
-import com.google.gwt.user.rebind.SourceWriter;
-import com.vaadin.shared.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ServerConnector;
-import com.vaadin.terminal.gwt.client.communication.InitializableServerRpc;
-import com.vaadin.terminal.gwt.client.communication.RpcProxy.RpcProxyCreator;
-
-public class RpcProxyCreatorGenerator extends Generator {
-
-    @Override
-    public String generate(TreeLogger logger, GeneratorContext ctx,
-            String requestedClassName) throws UnableToCompleteException {
-        logger.log(TreeLogger.DEBUG, "Running RpcProxyCreatorGenerator");
-        TypeOracle typeOracle = ctx.getTypeOracle();
-        assert (typeOracle != null);
-
-        JClassType requestedType = typeOracle.findType(requestedClassName);
-        if (requestedType == null) {
-            logger.log(TreeLogger.ERROR, "Unable to find metadata for type '"
-                    + requestedClassName + "'", null);
-            throw new UnableToCompleteException();
-        }
-        String packageName = requestedType.getPackage().getName();
-        String className = requestedType.getSimpleSourceName() + "Impl";
-
-        createType(logger, ctx, packageName, className);
-        return packageName + "." + className;
-    }
-
-    private void createType(TreeLogger logger, GeneratorContext context,
-            String packageName, String className) {
-        ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
-                packageName, className);
-
-        PrintWriter printWriter = context.tryCreate(logger,
-                composer.getCreatedPackage(),
-                composer.getCreatedClassShortName());
-        if (printWriter == null) {
-            // print writer is null if source code has already been generated
-            return;
-        }
-        Date date = new Date();
-        TypeOracle typeOracle = context.getTypeOracle();
-
-        // init composer, set class properties, create source writer
-        composer.addImport(GWT.class.getCanonicalName());
-        composer.addImport(ServerRpc.class.getCanonicalName());
-        composer.addImport(ServerConnector.class.getCanonicalName());
-        composer.addImport(InitializableServerRpc.class.getCanonicalName());
-        composer.addImport(IllegalArgumentException.class.getCanonicalName());
-        composer.addImplementedInterface(RpcProxyCreator.class
-                .getCanonicalName());
-
-        SourceWriter sourceWriter = composer.createSourceWriter(context,
-                printWriter);
-        sourceWriter.indent();
-
-        sourceWriter
-                .println("public <T extends ServerRpc> T create(Class<T> rpcInterface, ServerConnector connector) {");
-        sourceWriter.indent();
-
-        sourceWriter
-                .println("if (rpcInterface == null || connector == null) {");
-        sourceWriter.indent();
-        sourceWriter
-                .println("throw new IllegalArgumentException(\"RpcInterface and/or connector cannot be null\");");
-        sourceWriter.outdent();
-
-        JClassType initializableInterface = typeOracle.findType(ServerRpc.class
-                .getCanonicalName());
-
-        for (JClassType rpcType : initializableInterface.getSubtypes()) {
-            String rpcClassName = rpcType.getQualifiedSourceName();
-            if (InitializableServerRpc.class.getCanonicalName().equals(
-                    rpcClassName)) {
-                // InitializableClientToServerRpc is a special marker interface
-                // that should not get a generated class
-                continue;
-            }
-            sourceWriter.println("} else if (rpcInterface == " + rpcClassName
-                    + ".class) {");
-            sourceWriter.indent();
-            sourceWriter.println(rpcClassName + " rpc = GWT.create("
-                    + rpcClassName + ".class);");
-            sourceWriter.println("((" + InitializableServerRpc.class.getName()
-                    + ") rpc).initRpc(connector);");
-            sourceWriter.println("return (T) rpc;");
-            sourceWriter.outdent();
-        }
-
-        sourceWriter.println("} else {");
-        sourceWriter.indent();
-        sourceWriter
-                .println("throw new IllegalArgumentException(\"No RpcInterface of type \"+ rpcInterface.getName() + \" was found.\");");
-        sourceWriter.outdent();
-        // End of if
-        sourceWriter.println("}");
-        // End of method
-        sourceWriter.println("}");
-
-        // close generated class
-        sourceWriter.outdent();
-        sourceWriter.println("}");
-        // commit generated class
-        context.commit(logger, printWriter);
-        logger.log(Type.INFO, composer.getCreatedClassName() + " created in "
-                + (new Date().getTime() - date.getTime()) / 1000 + "seconds");
-
-    }
-}
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java
deleted file mode 100644 (file)
index 6d322c7..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2011 Vaadin Ltd.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.vaadin.terminal.gwt.widgetsetutils;
-
-import java.io.PrintWriter;
-
-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.JParameter;
-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.shared.annotations.Delayed;
-import com.vaadin.shared.communication.MethodInvocation;
-import com.vaadin.shared.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.ServerConnector;
-import com.vaadin.terminal.gwt.client.communication.InitializableServerRpc;
-
-/**
- * GWT generator that creates client side proxy classes for making RPC calls
- * from the client to the server.
- * 
- * GWT.create() calls for interfaces extending {@link ServerRpc} are affected,
- * and a proxy implementation is created. Note that the init(...) method of the
- * proxy must be called before the proxy is used.
- * 
- * @since 7.0
- */
-public class RpcProxyGenerator extends Generator {
-    @Override
-    public String generate(TreeLogger logger, GeneratorContext ctx,
-            String requestedClassName) throws UnableToCompleteException {
-        logger.log(TreeLogger.DEBUG, "Running RpcProxyGenerator", null);
-
-        TypeOracle typeOracle = ctx.getTypeOracle();
-        assert (typeOracle != null);
-
-        JClassType requestedType = typeOracle.findType(requestedClassName);
-        if (requestedType == null) {
-            logger.log(TreeLogger.ERROR, "Unable to find metadata for type '"
-                    + requestedClassName + "'", null);
-            throw new UnableToCompleteException();
-        }
-
-        String generatedClassName = "ServerRpc_"
-                + requestedType.getName().replaceAll("[$.]", "_");
-
-        JClassType initializableInterface = typeOracle
-                .findType(InitializableServerRpc.class.getCanonicalName());
-
-        ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
-                requestedType.getPackage().getName(), generatedClassName);
-        composer.addImplementedInterface(requestedType.getQualifiedSourceName());
-        composer.addImplementedInterface(initializableInterface
-                .getQualifiedSourceName());
-        composer.addImport(MethodInvocation.class.getCanonicalName());
-
-        PrintWriter printWriter = ctx.tryCreate(logger,
-                composer.getCreatedPackage(),
-                composer.getCreatedClassShortName());
-        if (printWriter != null) {
-            logger.log(Type.INFO, "Generating client proxy for RPC interface '"
-                    + requestedType.getQualifiedSourceName() + "'");
-            SourceWriter writer = composer.createSourceWriter(ctx, printWriter);
-
-            // constructor
-            writer.println("public " + generatedClassName + "() {}");
-
-            // initialization etc.
-            writeCommonFieldsAndMethods(logger, writer, typeOracle);
-
-            // actual proxy methods forwarding calls to the server
-            writeRemoteProxyMethods(logger, writer, typeOracle, requestedType,
-                    requestedType.isClassOrInterface().getInheritableMethods());
-
-            // End of class
-            writer.outdent();
-            writer.println("}");
-
-            ctx.commit(logger, printWriter);
-        }
-
-        return composer.getCreatedClassName();
-    }
-
-    private void writeCommonFieldsAndMethods(TreeLogger logger,
-            SourceWriter writer, TypeOracle typeOracle) {
-        JClassType applicationConnectionClass = typeOracle
-                .findType(ApplicationConnection.class.getCanonicalName());
-
-        // fields
-        writer.println("private " + ServerConnector.class.getName()
-                + " connector;");
-
-        // init method from the RPC interface
-        writer.println("public void initRpc(" + ServerConnector.class.getName()
-                + " connector) {");
-        writer.indent();
-        writer.println("this.connector = connector;");
-        writer.outdent();
-        writer.println("}");
-    }
-
-    private static void writeRemoteProxyMethods(TreeLogger logger,
-            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();
-
-            Delayed delayedAnnotation = m.getAnnotation(Delayed.class);
-            boolean delayed = delayedAnnotation != null;
-            boolean lastonly = delayed && delayedAnnotation.lastonly();
-
-            writer.print("this.connector.getConnection().addMethodInvocationToQueue(new MethodInvocation(this.connector.getConnectorId(), \""
-                    + requestedType.getQualifiedBinaryName() + "\", \"");
-            writer.print(m.getName());
-            writer.print("\", new Object[] {");
-            // new Object[] { ... } for parameters - autoboxing etc. by the
-            // compiler
-            JParameter[] parameters = m.getParameters();
-            boolean first = true;
-            for (JParameter p : parameters) {
-                if (!first) {
-                    writer.print(", ");
-                }
-                first = false;
-
-                writer.print(p.getName());
-            }
-            writer.println("}), " + delayed + ", " + lastonly + ");");
-
-            writer.outdent();
-            writer.println("}");
-        }
-    }
-}
index 3302fbc4fabb00209c85002e6c231c8660b9be8e..e93c72aa2f4b2e8d1e10cc83adba1b994d90958e 100644 (file)
@@ -36,8 +36,11 @@ public class ConnectorBundle {
     private final Map<JClassType, Set<JMethod>> needsReturnType = new HashMap<JClassType, Set<JMethod>>();
 
     private final Collection<TypeVisitor> visitors;
+
+    private final Set<JClassType> needsProxySupport = new HashSet<JClassType>();
     private final Map<JClassType, Set<JMethod>> needsInvoker = new HashMap<JClassType, Set<JMethod>>();
     private final Map<JClassType, Set<JMethod>> needsParamTypes = new HashMap<JClassType, Set<JMethod>>();
+    private final Map<JClassType, Set<JMethod>> needsDelayedInfo = new HashMap<JClassType, Set<JMethod>>();
 
     private ConnectorBundle(String name, ConnectorBundle previousBundle,
             Collection<TypeVisitor> visitors) {
@@ -268,4 +271,44 @@ public class ConnectorBundle {
     public Map<JClassType, Set<JMethod>> getNeedsParamTypes() {
         return Collections.unmodifiableMap(needsParamTypes);
     }
+
+    public void setNeedsProxySupport(JClassType type) {
+        if (!isNeedsProxySupport(type)) {
+            ensureVisited(type);
+            needsProxySupport.add(type);
+        }
+    }
+
+    private boolean isNeedsProxySupport(JClassType type) {
+        if (needsProxySupport.contains(type)) {
+            return true;
+        } else {
+            return previousBundle != null
+                    && previousBundle.isNeedsProxySupport(type);
+        }
+    }
+
+    public Set<JClassType> getNeedsProxySupport() {
+        return Collections.unmodifiableSet(needsProxySupport);
+    }
+
+    public void setNeedsDelayedInfo(JClassType type, JMethod method) {
+        if (!isNeedsDelayedInfo(type, method)) {
+            ensureVisited(type);
+            addMapping(needsDelayedInfo, type, method);
+        }
+    }
+
+    private boolean isNeedsDelayedInfo(JClassType type, JMethod method) {
+        if (hasMapping(needsDelayedInfo, type, method)) {
+            return true;
+        } else {
+            return previousBundle != null
+                    && previousBundle.isNeedsDelayedInfo(type, method);
+        }
+    }
+
+    public Map<JClassType, Set<JMethod>> getNeedsDelayedInfo() {
+        return Collections.unmodifiableMap(needsDelayedInfo);
+    }
 }
\ No newline at end of file
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ServerRpcVisitor.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ServerRpcVisitor.java
new file mode 100644 (file)
index 0000000..5505c70
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.terminal.gwt.widgetsetutils.metadata;
+
+import java.util.Set;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+
+public class ServerRpcVisitor extends TypeVisitor {
+    @Override
+    public void visitServerRpc(TreeLogger logger, JClassType type,
+            ConnectorBundle bundle) {
+        bundle.setNeedsProxySupport(type);
+
+        Set<? extends JClassType> superTypes = type
+                .getFlattenedSupertypeHierarchy();
+        for (JClassType subType : superTypes) {
+            if (subType.isInterface() != null) {
+                JMethod[] methods = subType.getMethods();
+                for (JMethod method : methods) {
+                    bundle.setNeedsDelayedInfo(type, method);
+                }
+            }
+        }
+    }
+}
index e25c812e5bae18fbc88b2deccd70ba0b463b2aec..fe9643232e1c799492cdb377219418c4c03fa5c3 100644 (file)
                        class="com.vaadin.terminal.gwt.client.ui.dd.VAcceptCriterionFactory" />
        </generate-with>
 
-       <!-- Generate client side proxies for client to server RPC interfaces -->
-       <generate-with
-               class="com.vaadin.terminal.gwt.widgetsetutils.RpcProxyGenerator">
-               <when-type-assignable
-                       class="com.vaadin.shared.communication.ServerRpc" />
-       </generate-with>
-
-       <!-- Generate client side proxies for client to server RPC interfaces -->
-       <generate-with
-               class="com.vaadin.terminal.gwt.widgetsetutils.RpcProxyCreatorGenerator">
-               <when-type-assignable
-                       class="com.vaadin.terminal.gwt.client.communication.RpcProxy.RpcProxyCreator" />
-       </generate-with>
-       
        <generate-with class="com.vaadin.terminal.gwt.widgetsetutils.ConnectorBundleLoaderFactory">
                <when-type-assignable class="com.vaadin.terminal.gwt.client.metadata.ConnectorBundleLoader" />
        </generate-with>
index 8ba8f0afab3be3ca596051a4670986e6b7fda2cc..9b58eb1295dc901ab9eb2137dd7cb409c13b18b4 100644 (file)
@@ -208,6 +208,9 @@ public class ApplicationConnection {
     }
 
     public ApplicationConnection() {
+        // Assuming Root data is eagerly loaded
+        ConnectorBundleLoader.get().loadBundle(
+                ConnectorBundleLoader.EAGER_BUNDLE_NAME, null);
         rootConnector = GWT.create(RootConnector.class);
         rpcManager = GWT.create(RpcManager.class);
         layoutManager = GWT.create(LayoutManager.class);
@@ -241,10 +244,6 @@ public class ApplicationConnection {
 
         initializeClientHooks();
 
-        // Assuming Root data is eagerly loaded
-        ConnectorBundleLoader.get().loadBundle(
-                ConnectorBundleLoader.EAGER_BUNDLE_NAME, null);
-
         rootConnector.init(cnf.getRootPanelId(), this);
         showLoadingIndicator();
     }
diff --git a/client/src/com/vaadin/terminal/gwt/client/communication/InitializableServerRpc.java b/client/src/com/vaadin/terminal/gwt/client/communication/InitializableServerRpc.java
deleted file mode 100644 (file)
index 65887bf..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011 Vaadin Ltd.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.terminal.gwt.client.communication;
-
-import com.vaadin.shared.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ServerConnector;
-
-/**
- * Initialization support for client to server RPC interfaces.
- * 
- * This is in a separate interface used by the GWT generator class. The init
- * method is not in {@link ServerRpc} because then also server side proxies
- * would have to implement the initialization method.
- * 
- * @since 7.0
- */
-public interface InitializableServerRpc extends ServerRpc {
-    /**
-     * Associates the RPC proxy with a connector. Called by generated code.
-     * Should never be called manually.
-     * 
-     * @param connector
-     *            The connector the ServerRPC instance is assigned to.
-     */
-    public void initRpc(ServerConnector connector);
-}
\ No newline at end of file
index 45939eb54eb530f343cdeefbdb170bbe3e8f54a5..5b9bcff6a4e964883ccdc2bb175211e53c79f5e3 100644 (file)
@@ -76,14 +76,14 @@ public class RpcManager {
 
     public Type[] getParameterTypes(MethodInvocation invocation) {
         Method method = getMethod(invocation);
-        Type[] parameterTypes = method.getParameterTypes();
-        if (parameterTypes == null) {
+        try {
+            Type[] parameterTypes = method.getParameterTypes();
+            return parameterTypes;
+        } catch (NoDataException e) {
             throw new IllegalStateException("There is no information about "
                     + method.getSignature()
-                    + ". Did you remember to compile the right widgetset?");
-
+                    + ". Did you remember to compile the right widgetset?", e);
         }
-        return parameterTypes;
     }
 
     public void parseAndApplyInvocation(JSONArray rpcCall,
index 226594adc6d91cc0a41b8d9237272bd252de4b95..e9dc6ab7fdbb4e161f30f93042db7d0866ea6a91 100644 (file)
  */
 package com.vaadin.terminal.gwt.client.communication;
 
-import com.google.gwt.core.client.GWT;
+import com.vaadin.shared.communication.MethodInvocation;
 import com.vaadin.shared.communication.ServerRpc;
 import com.vaadin.terminal.gwt.client.ServerConnector;
+import com.vaadin.terminal.gwt.client.metadata.InvokationHandler;
+import com.vaadin.terminal.gwt.client.metadata.Method;
+import com.vaadin.terminal.gwt.client.metadata.NoDataException;
+import com.vaadin.terminal.gwt.client.metadata.TypeData;
 
 /**
  * Class for creating proxy instances for Client to Server RPC.
@@ -26,25 +30,38 @@ import com.vaadin.terminal.gwt.client.ServerConnector;
  */
 public class RpcProxy {
 
-    private static RpcProxyCreator impl = GWT.create(RpcProxyCreator.class);
-
-    /**
-     * Create a proxy class for the given Rpc interface and assign it to the
-     * given connector.
-     * 
-     * @param rpcInterface
-     *            The rpc interface to construct a proxy for
-     * @param connector
-     *            The connector this proxy is connected to
-     * @return A proxy class used for calling Rpc methods.
-     */
     public static <T extends ServerRpc> T create(Class<T> rpcInterface,
             ServerConnector connector) {
-        return impl.create(rpcInterface, connector);
+        try {
+            return (T) TypeData.getType(rpcInterface).createProxy(
+                    new RpcInvokationHandler(rpcInterface, connector));
+        } catch (NoDataException e) {
+            throw new IllegalStateException("There is no information about "
+                    + rpcInterface
+                    + ". Did you forget to compile the widgetset?");
+        }
     }
 
-    public interface RpcProxyCreator {
-        <T extends ServerRpc> T create(Class<T> rpcInterface,
-                ServerConnector connector);
+    private static final class RpcInvokationHandler implements
+            InvokationHandler {
+        private final Class<?> rpcInterface;
+        private final ServerConnector connector;
+
+        private RpcInvokationHandler(Class<?> rpcInterface,
+                ServerConnector connector) {
+            this.rpcInterface = rpcInterface;
+            this.connector = connector;
+        }
+
+        @Override
+        public Object invoke(Object target, Method method, Object[] params) {
+            MethodInvocation invocation = new MethodInvocation(
+                    connector.getConnectorId(), rpcInterface.getName(),
+                    method.getName(), params);
+            connector.getConnection().addMethodInvocationToQueue(invocation,
+                    method.isDelayed(), method.isLastonly());
+            // No RPC iface should have a return value
+            return null;
+        }
     }
 }
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/InvokationHandler.java b/client/src/com/vaadin/terminal/gwt/client/metadata/InvokationHandler.java
new file mode 100644 (file)
index 0000000..2b1153a
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.terminal.gwt.client.metadata;
+
+public interface InvokationHandler {
+    public Object invoke(Object target, Method method, Object[] params);
+}
index 588e736da3624254730de4f82d053eda99c06fa6..527e8a29d205c3d3287e0563dfc3390d56cc9550 100644 (file)
@@ -56,8 +56,16 @@ public class Method {
         return getSignature().hashCode();
     }
 
-    public Type[] getParameterTypes() {
+    public Type[] getParameterTypes() throws NoDataException {
         return TypeDataStore.getParamTypes(this);
     }
 
+    public boolean isDelayed() {
+        return TypeDataStore.isDelayed(this);
+    }
+
+    public boolean isLastonly() {
+        return TypeDataStore.isLastonly(this);
+    }
+
 }
diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/ProxyHandler.java b/client/src/com/vaadin/terminal/gwt/client/metadata/ProxyHandler.java
new file mode 100644 (file)
index 0000000..cc8168a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.terminal.gwt.client.metadata;
+
+public interface ProxyHandler {
+
+    Object createProxy(InvokationHandler invokationHandler);
+
+}
index dfd504983c8d5e55a49a9bc90ce5fd01dbb5f8da..2dc5182845c03d961b28a5d161b39fae5c7bce1a 100644 (file)
@@ -76,4 +76,10 @@ public class Type {
         return getSignature().hashCode();
     }
 
+    public Object createProxy(InvokationHandler invokationHandler)
+            throws NoDataException {
+        return TypeDataStore.get().getProxyHandler(this)
+                .createProxy(invokationHandler);
+    }
+
 }
index 4b99250465a7476b1ff2fae858815a8b3e40bb9f..f056e46d2d7d76c48298437e9c0fd9a8b74ab8be 100644 (file)
@@ -5,13 +5,20 @@
 package com.vaadin.terminal.gwt.client.metadata;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 public class TypeDataStore {
     private static final String CONSTRUCTOR_NAME = "!new";
 
     private final Map<String, Class<?>> identifiers = new HashMap<String, Class<?>>();
 
+    private final Map<Type, ProxyHandler> proxyHandlers = new HashMap<Type, ProxyHandler>();
+
+    private final Set<Method> delayedMethods = new HashSet<Method>();
+    private final Set<Method> lastonlyMethods = new HashSet<Method>();
+
     private final Map<Method, Type> returnTypes = new HashMap<Method, Type>();
     private final Map<Method, Invoker> invokers = new HashMap<Method, Invoker>();
     private final Map<Method, Type[]> paramTypes = new HashMap<Method, Type[]>();
@@ -94,8 +101,13 @@ public class TypeDataStore {
         invokers.put(new Method(getType(type), methodName), invoker);
     }
 
-    public static Type[] getParamTypes(Method method) {
-        return get().paramTypes.get(method);
+    public static Type[] getParamTypes(Method method) throws NoDataException {
+        Type[] types = get().paramTypes.get(method);
+        if (types == null) {
+            throw new NoDataException("There are no parameter type data for "
+                    + method.getSignature());
+        }
+        return types;
     }
 
     public void setParamTypes(Class<?> type, String methodName,
@@ -106,4 +118,34 @@ public class TypeDataStore {
     public static boolean hasIdentifier(String identifier) {
         return get().identifiers.containsKey(identifier);
     }
+
+    public static ProxyHandler getProxyHandler(Type type)
+            throws NoDataException {
+        ProxyHandler proxyHandler = get().proxyHandlers.get(type);
+        if (proxyHandler == null) {
+            throw new NoDataException("No proxy handler for "
+                    + type.getSignature());
+        }
+        return proxyHandler;
+    }
+
+    public void setProxyHandler(Class<?> type, ProxyHandler proxyHandler) {
+        proxyHandlers.put(getType(type), proxyHandler);
+    }
+
+    public static boolean isDelayed(Method method) {
+        return get().delayedMethods.contains(method);
+    }
+
+    public void setDelayed(Class<?> type, String methodName) {
+        delayedMethods.add(getType(type).getMethod(methodName));
+    }
+
+    public static boolean isLastonly(Method method) {
+        return get().lastonlyMethods.contains(method);
+    }
+
+    public void setLastonly(Class<?> clazz, String methodName) {
+        lastonlyMethods.add(getType(clazz).getMethod(methodName));
+    }
 }