@@ -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); | |||
} |
@@ -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"); | |||
} | |||
} |
@@ -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("}"); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -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> |
@@ -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(); | |||
} |
@@ -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); | |||
} |
@@ -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, |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -76,4 +76,10 @@ public class Type { | |||
return getSignature().hashCode(); | |||
} | |||
public Object createProxy(InvokationHandler invokationHandler) | |||
throws NoDataException { | |||
return TypeDataStore.get().getProxyHandler(this) | |||
.createProxy(invokationHandler); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |