From: Leif Åstrand Date: Tue, 21 Aug 2012 13:51:33 +0000 (+0300) Subject: Use ConnectorBundle for ServerRpc handling (#9371) X-Git-Tag: 7.0.0.beta1~221^2~14 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e345e1820aa0e0fe551cca86d6d28b906beb8937;p=vaadin-framework.git Use ConnectorBundle for ServerRpc handling (#9371) --- diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java index 8cb04d9370..9f830d4a8d 100644 --- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java +++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java @@ -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> needsDelayedInfo = bundle + .getNeedsDelayedInfo(); + Set>> entrySet = needsDelayedInfo + .entrySet(); + for (Entry> entry : entrySet) { + JClassType type = entry.getKey(); + Set 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 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 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 visitors = Arrays. 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 index eccc6461c9..0000000000 --- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyCreatorGenerator.java +++ /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 create(Class 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 index 6d322c734e..0000000000 --- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java +++ /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("}"); - } - } -} diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java index 3302fbc4fa..e93c72aa2f 100644 --- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java +++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java @@ -36,8 +36,11 @@ public class ConnectorBundle { private final Map> needsReturnType = new HashMap>(); private final Collection visitors; + + private final Set needsProxySupport = new HashSet(); private final Map> needsInvoker = new HashMap>(); private final Map> needsParamTypes = new HashMap>(); + private final Map> needsDelayedInfo = new HashMap>(); private ConnectorBundle(String name, ConnectorBundle previousBundle, Collection visitors) { @@ -268,4 +271,44 @@ public class ConnectorBundle { public Map> 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 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> 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 index 0000000000..5505c70dc3 --- /dev/null +++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ServerRpcVisitor.java @@ -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 superTypes = type + .getFlattenedSupertypeHierarchy(); + for (JClassType subType : superTypes) { + if (subType.isInterface() != null) { + JMethod[] methods = subType.getMethods(); + for (JMethod method : methods) { + bundle.setNeedsDelayedInfo(type, method); + } + } + } + } +} diff --git a/client/src/com/vaadin/Vaadin.gwt.xml b/client/src/com/vaadin/Vaadin.gwt.xml index e25c812e5b..fe9643232e 100644 --- a/client/src/com/vaadin/Vaadin.gwt.xml +++ b/client/src/com/vaadin/Vaadin.gwt.xml @@ -41,20 +41,6 @@ class="com.vaadin.terminal.gwt.client.ui.dd.VAcceptCriterionFactory" /> - - - - - - - - - - diff --git a/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index 8ba8f0afab..9b58eb1295 100644 --- a/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/client/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -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 index 65887bf62e..0000000000 --- a/client/src/com/vaadin/terminal/gwt/client/communication/InitializableServerRpc.java +++ /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 diff --git a/client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java b/client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java index 45939eb54e..5b9bcff6a4 100644 --- a/client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java +++ b/client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java @@ -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, diff --git a/client/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java b/client/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java index 226594adc6..e9dc6ab7fd 100644 --- a/client/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java +++ b/client/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java @@ -15,9 +15,13 @@ */ 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 create(Class 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 create(Class 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 index 0000000000..2b1153ad97 --- /dev/null +++ b/client/src/com/vaadin/terminal/gwt/client/metadata/InvokationHandler.java @@ -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); +} diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/Method.java b/client/src/com/vaadin/terminal/gwt/client/metadata/Method.java index 588e736da3..527e8a29d2 100644 --- a/client/src/com/vaadin/terminal/gwt/client/metadata/Method.java +++ b/client/src/com/vaadin/terminal/gwt/client/metadata/Method.java @@ -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 index 0000000000..cc8168a8ff --- /dev/null +++ b/client/src/com/vaadin/terminal/gwt/client/metadata/ProxyHandler.java @@ -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); + +} diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/Type.java b/client/src/com/vaadin/terminal/gwt/client/metadata/Type.java index dfd504983c..2dc5182845 100644 --- a/client/src/com/vaadin/terminal/gwt/client/metadata/Type.java +++ b/client/src/com/vaadin/terminal/gwt/client/metadata/Type.java @@ -76,4 +76,10 @@ public class Type { return getSignature().hashCode(); } + public Object createProxy(InvokationHandler invokationHandler) + throws NoDataException { + return TypeDataStore.get().getProxyHandler(this) + .createProxy(invokationHandler); + } + } diff --git a/client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java b/client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java index 4b99250465..f056e46d2d 100644 --- a/client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java +++ b/client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java @@ -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> identifiers = new HashMap>(); + private final Map proxyHandlers = new HashMap(); + + private final Set delayedMethods = new HashSet(); + private final Set lastonlyMethods = new HashSet(); + private final Map returnTypes = new HashMap(); private final Map invokers = new HashMap(); private final Map paramTypes = new HashMap(); @@ -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)); + } }