Browse Source

Refactor RpcManager to provide info about parameter types (#8879)

This is an intermediate step towards decoding everything received from
the server based on its declared type.
tags/7.0.0.alpha3
Leif Åstrand 12 years ago
parent
commit
dc7e238f2d

+ 2
- 2
src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml View 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

+ 20
- 0
src/com/vaadin/terminal/gwt/client/communication/GeneratedRpcMethodProvider.java View File

@@ -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();
}

+ 56
- 3
src/com/vaadin/terminal/gwt/client/communication/RpcManager.java View 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();
}

}

+ 32
- 0
src/com/vaadin/terminal/gwt/client/communication/RpcMethod.java View File

@@ -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);

}

+ 40
- 0
src/com/vaadin/terminal/gwt/client/communication/Type.java View File

@@ -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;
}

}

src/com/vaadin/terminal/gwt/widgetsetutils/RpcManagerGenerator.java → src/com/vaadin/terminal/gwt/widgetsetutils/GeneratedRpcMethodProviderGenerator.java View File

@@ -16,15 +16,15 @@ 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.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.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
@@ -32,7 +32,7 @@ import com.vaadin.terminal.gwt.client.communication.RpcManager;
*
* @since 7.0
*/
public class RpcManagerGenerator extends Generator {
public class GeneratedRpcMethodProviderGenerator extends Generator {

@Override
public String generate(TreeLogger logger, GeneratorContext context,
@@ -90,12 +90,24 @@ public class RpcManagerGenerator extends Generator {
ClassSourceFileComposerFactory composer = null;
composer = new ClassSourceFileComposerFactory(packageName, className);
composer.addImport("com.google.gwt.core.client.GWT");
composer.addImplementedInterface(RpcManager.class.getName());
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<JClassType> rpcInterfaces = new ArrayList<JClassType>();
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
@@ -104,81 +116,56 @@ public class RpcManagerGenerator extends Generator {
// 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 = "";

// RpcMethod(String interfaceName, String methodName,
// Type... parameterTypes)
sourceWriter.print("list.add(new RpcMethod(\""
+ type.getQualifiedSourceName() + "\", \""
+ method.getName() + "\"");
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 + ", ";
}
for (JType parameter : parameterTypes) {
sourceWriter.print(", ");
writeTypeCreator(sourceWriter, parameter);
}
sourceWriter.println(") {");
sourceWriter.indent();

sourceWriter
.println(ServerConnector.class.getName()
+ " connector = connectorMap.getConnector(invocation.getConnectorId());");
sourceWriter
.println("for ("
+ ClientRpc.class.getName()
+ " rpcImplementation : connector.getRpcImplementations(\""
+ type.getQualifiedSourceName() + "\")) {");
.println("public void applyInvocation(ClientRpc target, Object... parameters) {");
sourceWriter.indent();
sourceWriter.println("((" + type.getQualifiedSourceName()
+ ") rpcImplementation)." + method.getName() + "("
+ paramString + ");");

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.println("return;");
sourceWriter.outdent();
sourceWriter.println("}");
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();
sourceWriter.println("return list;");

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("}");
sourceWriter.println();

// close generated class
sourceWriter.outdent();
@@ -191,6 +178,24 @@ public class RpcManagerGenerator extends Generator {

}

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("\\.", "_");
}

Loading…
Cancel
Save