diff options
author | Leif Åstrand <leif@vaadin.com> | 2012-06-14 22:57:28 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2012-06-14 22:57:28 +0300 |
commit | 51ce4a2535146a3b8861bd02f655c18d9a397522 (patch) | |
tree | 2c4421863c5255b1595111c6e968b0a84f1c9f4b /src/com | |
parent | 72c0f66e2aa588acbb517e6d9b482c7a75faf9f1 (diff) | |
download | vaadin-framework-51ce4a2535146a3b8861bd02f655c18d9a397522.tar.gz vaadin-framework-51ce4a2535146a3b8861bd02f655c18d9a397522.zip |
Implement js rpc proxy objects and wildcard rpc support (#8888)
Diffstat (limited to 'src/com')
8 files changed, 176 insertions, 24 deletions
diff --git a/src/com/vaadin/terminal/AbstractJavaScriptExtension.java b/src/com/vaadin/terminal/AbstractJavaScriptExtension.java index 22c8dd4561..a2f8019858 100644 --- a/src/com/vaadin/terminal/AbstractJavaScriptExtension.java +++ b/src/com/vaadin/terminal/AbstractJavaScriptExtension.java @@ -11,6 +11,13 @@ public class AbstractJavaScriptExtension extends AbstractExtension { private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper( this); + @Override + protected <T> void registerRpc(T implementation, + java.lang.Class<T> rpcInterfaceType) { + super.registerRpc(implementation, rpcInterfaceType); + callbackHelper.registerRpc(rpcInterfaceType); + } + protected void registerCallback(String functionName, JavaScriptCallback javaScriptCallback) { callbackHelper.registerCallback(functionName, javaScriptCallback); diff --git a/src/com/vaadin/terminal/JavaScriptCallbackHelper.java b/src/com/vaadin/terminal/JavaScriptCallbackHelper.java index c1da8b36ba..eabbcf4925 100644 --- a/src/com/vaadin/terminal/JavaScriptCallbackHelper.java +++ b/src/com/vaadin/terminal/JavaScriptCallbackHelper.java @@ -7,7 +7,9 @@ package com.vaadin.terminal; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import com.vaadin.external.json.JSONArray; import com.vaadin.external.json.JSONException; @@ -75,4 +77,24 @@ public class JavaScriptCallbackHelper { connector.requestRepaint(); } + public void registerRpc(Class<?> rpcInterfaceType) { + if (rpcInterfaceType == JavaScriptCallbackRpc.class) { + // Ignore + return; + } + Map<String, Set<String>> rpcInterfaces = getConnectorState() + .getRpcInterfaces(); + String interfaceName = rpcInterfaceType.getName(); + if (!rpcInterfaces.containsKey(interfaceName)) { + Set<String> methodNames = new HashSet<String>(); + + for (Method method : rpcInterfaceType.getMethods()) { + methodNames.add(method.getName()); + } + + rpcInterfaces.put(interfaceName, methodNames); + connector.requestRepaint(); + } + } + } diff --git a/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java b/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java index d07cf0036c..77adcd4217 100644 --- a/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java +++ b/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java @@ -5,6 +5,10 @@ package com.vaadin.terminal.gwt.client; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import com.google.gwt.core.client.JavaScriptObject; @@ -18,6 +22,8 @@ public class JavaScriptConnectorHelper { public interface JavaScriptConnectorState { public Set<String> getCallbackNames(); + + public Map<String, Set<String>> getRpcInterfaces(); } private final ServerConnector connector; @@ -25,26 +31,80 @@ public class JavaScriptConnectorHelper { .createObject(); private final JavaScriptObject rpcMap = JavaScriptObject.createObject(); + private final Map<String, JavaScriptObject> rpcObjects = new HashMap<String, JavaScriptObject>(); + private final Map<String, Set<String>> rpcMethods = new HashMap<String, Set<String>>(); + private JavaScriptObject connectorWrapper; private int tag; + private boolean inited = false; + public JavaScriptConnectorHelper(ServerConnector connector) { this.connector = connector; + + // Wildcard rpc object + rpcObjects.put("", JavaScriptObject.createObject()); + connector.addStateChangeHandler(new StateChangeHandler() { public void onStateChanged(StateChangeEvent stateChangeEvent) { JavaScriptObject wrapper = getConnectorWrapper(); + JavaScriptConnectorState state = getConnectorState(); - for (String callback : getConnectorState().getCallbackNames()) { + for (String callback : state.getCallbackNames()) { ensureCallback(JavaScriptConnectorHelper.this, wrapper, callback); } + for (Entry<String, Set<String>> entry : state + .getRpcInterfaces().entrySet()) { + String rpcName = entry.getKey(); + String jsName = getJsInterfaceName(rpcName); + if (!rpcObjects.containsKey(jsName)) { + Set<String> methods = entry.getValue(); + rpcObjects.put(jsName, + createRpcObject(rpcName, methods)); + + // Init all methods for wildcard rpc + for (String method : methods) { + JavaScriptObject wildcardRpcObject = rpcObjects + .get(""); + Set<String> interfaces = rpcMethods.get(method); + if (interfaces == null) { + interfaces = new HashSet<String>(); + rpcMethods.put(method, interfaces); + attachRpcMethod(wildcardRpcObject, null, method); + } + interfaces.add(rpcName); + } + } + } + + // Init after setting up callbacks & rpc + if (!inited) { + init(); + inited = true; + } + fireNativeStateChange(wrapper); } }); } - public boolean init() { + private static String getJsInterfaceName(String rpcName) { + return rpcName.replace('$', '.'); + } + + protected JavaScriptObject createRpcObject(String iface, Set<String> methods) { + JavaScriptObject object = JavaScriptObject.createObject(); + + for (String method : methods) { + attachRpcMethod(object, iface, method); + } + + return object; + } + + private boolean init() { ApplicationConfiguration conf = connector.getConnection() .getConfiguration(); ArrayList<String> attemptedNames = new ArrayList<String>(); @@ -94,7 +154,7 @@ public class JavaScriptConnectorHelper { protected JavaScriptObject createConnectorWrapper() { return createConnectorWrapper(this, nativeState, rpcMap, - connector.getConnectorId()); + connector.getConnectorId(), rpcObjects); } private static native void fireNativeStateChange( @@ -107,7 +167,8 @@ public class JavaScriptConnectorHelper { private static native JavaScriptObject createConnectorWrapper( JavaScriptConnectorHelper h, JavaScriptObject nativeState, - JavaScriptObject registeredRpc, String connectorId) + JavaScriptObject registeredRpc, String connectorId, + Map<String, JavaScriptObject> rpcObjects) /*-{ return { 'getConnectorId': function() { @@ -116,12 +177,18 @@ public class JavaScriptConnectorHelper { 'getState': function() { return nativeState; }, - 'getRpcProxyFunction': function(iface, method) { - return $entry(function() { - h.@com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper::fireRpc(Ljava/lang/String;Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;)(iface, method, arguments); - }); + 'getRpcProxy': function(iface) { + if (!iface) { + iface = ''; + } + return rpcObjects.@java.util.Map::get(Ljava/lang/Object;)(iface); }, 'registerRpc': function(iface, rpcHandler) { + //registerRpc(handler) -> registerRpc('', handler); + if (!rpcHandler) { + rpcHandler = iface; + iface = ''; + } if (!registeredRpc[iface]) { registeredRpc[iface] = []; } @@ -130,8 +197,21 @@ public class JavaScriptConnectorHelper { }; }-*/; + private native void attachRpcMethod(JavaScriptObject rpc, String iface, + String method) + /*-{ + var self = this; + rpc[method] = $entry(function() { + self.@com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper::fireRpc(Ljava/lang/String;Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;)(iface, method, arguments); + }); + }-*/; + private void fireRpc(String iface, String method, JsArray<JavaScriptObject> arguments) { + if (iface == null) { + iface = findWildcardInterface(method); + } + JSONArray argumentsArray = new JSONArray(arguments); Object[] parameters = new Object[arguments.length()]; for (int i = 0; i < parameters.length; i++) { @@ -142,6 +222,29 @@ public class JavaScriptConnectorHelper { parameters), true); } + private String findWildcardInterface(String method) { + Set<String> interfaces = rpcMethods.get(method); + if (interfaces.size() == 1) { + return interfaces.iterator().next(); + } else { + // TODO Resolve conflicts using argument count and types + String interfaceList = ""; + for (String iface : interfaces) { + if (interfaceList.length() != 0) { + interfaceList += ", "; + } + interfaceList += getJsInterfaceName(iface); + } + + throw new IllegalStateException( + "Can not call method " + + method + + " for wildcard rpc proxy because the function is defined for multiple rpc interfaces: " + + interfaceList + + ". Retrieve a rpc proxy for a specific interface using getRpcProxy(interfaceName) to use the function."); + } + } + private void fireCallback(String name, JsArray<JavaScriptObject> arguments) { MethodInvocation invocation = new MethodInvocation( connector.getConnectorId(), @@ -181,18 +284,20 @@ public class JavaScriptConnectorHelper { public void invokeJsRpc(MethodInvocation invocation, JSONArray parametersJson) { - if ("com.vaadin.ui.JavaScript$JavaScriptCallbackRpc".equals(invocation - .getInterfaceName()) - && "call".equals(invocation.getMethodName())) { + String iface = invocation.getInterfaceName(); + String method = invocation.getMethodName(); + if ("com.vaadin.ui.JavaScript$JavaScriptCallbackRpc".equals(iface) + && "call".equals(method)) { String callbackName = parametersJson.get(0).isString() .stringValue(); JavaScriptObject arguments = parametersJson.get(1).isArray() .getJavaScriptObject(); invokeCallback(getConnectorWrapper(), callbackName, arguments); } else { - invokeJsRpc(rpcMap, invocation.getInterfaceName(), - invocation.getMethodName(), - parametersJson.getJavaScriptObject()); + JavaScriptObject arguments = parametersJson.getJavaScriptObject(); + invokeJsRpc(rpcMap, iface, method, arguments); + // Also invoke wildcard interface + invokeJsRpc(rpcMap, "", method, arguments); } } diff --git a/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java b/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java index 47aa7eab28..e3dafab9bd 100644 --- a/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java +++ b/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java @@ -15,11 +15,6 @@ public class JavaScriptExtension extends AbstractExtensionConnector implements private final JavaScriptConnectorHelper helper = new JavaScriptConnectorHelper( this); - @Override - protected void init() { - helper.init(); - } - public JavaScriptConnectorHelper getJavascriptConnectorHelper() { return helper; } diff --git a/src/com/vaadin/terminal/gwt/client/JavaScriptExtensionState.java b/src/com/vaadin/terminal/gwt/client/JavaScriptExtensionState.java index fecf24d450..e7bfbc4bb2 100644 --- a/src/com/vaadin/terminal/gwt/client/JavaScriptExtensionState.java +++ b/src/com/vaadin/terminal/gwt/client/JavaScriptExtensionState.java @@ -4,7 +4,9 @@ package com.vaadin.terminal.gwt.client; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper.JavaScriptConnectorState; @@ -14,6 +16,7 @@ public class JavaScriptExtensionState extends SharedState implements JavaScriptConnectorState { private Set<String> callbackNames = new HashSet<String>(); + private Map<String, Set<String>> rpcInterfaces = new HashMap<String, Set<String>>(); public Set<String> getCallbackNames() { return callbackNames; @@ -23,4 +26,11 @@ public class JavaScriptExtensionState extends SharedState implements this.callbackNames = callbackNames; } + public Map<String, Set<String>> getRpcInterfaces() { + return rpcInterfaces; + } + + public void setRpcInterfaces(Map<String, Set<String>> rpcInterfaces) { + this.rpcInterfaces = rpcInterfaces; + } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java index ecab58bb9a..47afe95771 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java @@ -29,11 +29,6 @@ public class JavaScriptComponentConnector extends AbstractComponentConnector } }; - @Override - protected void init() { - helper.init(); - } - private static native void addGetWidgetElement( JavaScriptObject connectorWrapper, Element element) /*-{ diff --git a/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentState.java b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentState.java index bc8ed08bba..6728f85ec9 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentState.java +++ b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentState.java @@ -4,7 +4,9 @@ package com.vaadin.terminal.gwt.client.ui; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import com.vaadin.terminal.gwt.client.ComponentState; @@ -14,6 +16,7 @@ public class JavaScriptComponentState extends ComponentState implements JavaScriptConnectorState { private Set<String> callbackNames = new HashSet<String>(); + private Map<String, Set<String>> rpcInterfaces = new HashMap<String, Set<String>>(); public Set<String> getCallbackNames() { return callbackNames; @@ -23,4 +26,12 @@ public class JavaScriptComponentState extends ComponentState implements this.callbackNames = callbackNames; } + public Map<String, Set<String>> getRpcInterfaces() { + return rpcInterfaces; + } + + public void setRpcInterfaces(Map<String, Set<String>> rpcInterfaces) { + this.rpcInterfaces = rpcInterfaces; + } + } diff --git a/src/com/vaadin/ui/AbstractJavaScriptComponent.java b/src/com/vaadin/ui/AbstractJavaScriptComponent.java index e5759a1efc..343caf4abb 100644 --- a/src/com/vaadin/ui/AbstractJavaScriptComponent.java +++ b/src/com/vaadin/ui/AbstractJavaScriptComponent.java @@ -10,6 +10,13 @@ public class AbstractJavaScriptComponent extends AbstractComponent { private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper( this); + @Override + protected <T> void registerRpc(T implementation, + java.lang.Class<T> rpcInterfaceType) { + super.registerRpc(implementation, rpcInterfaceType); + callbackHelper.registerRpc(rpcInterfaceType); + } + protected void registerCallback(String functionName, JavaScriptCallback javascriptCallback) { callbackHelper.registerCallback(functionName, javascriptCallback); |