/* @VaadinApache2LicenseForJavaFiles@ */ 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.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.ServerConnector; import com.vaadin.terminal.gwt.client.communication.InitializableServerRpc; import com.vaadin.terminal.gwt.client.communication.MethodInvocation; import com.vaadin.terminal.gwt.client.communication.ServerRpc; /** * 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(); 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("}), true);"); writer.outdent(); writer.println("}"); } } }