Browse Source

Use ConnectorBundle for ServerRpc handling (#9371)

tags/7.0.0.beta1
Leif Åstrand 11 years ago
parent
commit
e345e1820a

+ 116
- 4
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java View 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);
}

+ 0
- 138
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyCreatorGenerator.java View File

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

}
}

+ 0
- 159
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java View File

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

+ 43
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java View 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);
}
}

+ 42
- 0
client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ServerRpcVisitor.java View File

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

+ 0
- 14
client/src/com/vaadin/Vaadin.gwt.xml View File

@@ -41,20 +41,6 @@
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>

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

+ 0
- 39
client/src/com/vaadin/terminal/gwt/client/communication/InitializableServerRpc.java View File

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

+ 5
- 5
client/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java View 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,

+ 34
- 17
client/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java View File

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

+ 21
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/InvokationHandler.java View File

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

+ 9
- 1
client/src/com/vaadin/terminal/gwt/client/metadata/Method.java View 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);
}

}

+ 23
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/ProxyHandler.java View File

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

}

+ 6
- 0
client/src/com/vaadin/terminal/gwt/client/metadata/Type.java View 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);
}

}

+ 44
- 2
client/src/com/vaadin/terminal/gwt/client/metadata/TypeDataStore.java View 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));
}
}

Loading…
Cancel
Save