]> source.dussan.org Git - vaadin-framework.git/commitdiff
Made it possible to find out RPC parameter types (#8667)
authorArtur <Artur@Storm>
Wed, 18 Apr 2012 07:09:53 +0000 (10:09 +0300)
committerArtur Signell <artur@vaadin.com>
Wed, 18 Apr 2012 20:09:07 +0000 (23:09 +0300)
Refactored legacy change variables handling to
LegacyChangeVariablesInvocation

src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
src/com/vaadin/terminal/gwt/server/JsonCodec.java
src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/server/RpcManager.java
src/com/vaadin/terminal/gwt/server/ServerRPCMethodInvocation.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/server/ServerRpcManager.java

index f4305ffcaaeaa3de2bfbbd3b5a529de3946dd4bd..b77477a76a0ae6c62147cc7cbdd71376e5cf6560 100644 (file)
@@ -17,14 +17,19 @@ public class MethodInvocation {
     private final String connectorId;
     private final String interfaceName;
     private final String methodName;
-    private final Object[] parameters;
+    private Object[] parameters;
 
     public MethodInvocation(String connectorId, String interfaceName,
-            String methodName, Object[] parameters) {
+            String methodName) {
         this.connectorId = connectorId;
         this.interfaceName = interfaceName;
         this.methodName = methodName;
-        this.parameters = parameters;
+    }
+
+    public MethodInvocation(String connectorId, String interfaceName,
+            String methodName, Object[] parameters) {
+        this(connectorId, interfaceName, methodName);
+        setParameters(parameters);
     }
 
     public String getConnectorId() {
@@ -43,9 +48,14 @@ public class MethodInvocation {
         return parameters;
     }
 
+    public void setParameters(Object[] parameters) {
+        this.parameters = parameters;
+    }
+
     @Override
     public String toString() {
         return connectorId + ":" + interfaceName + "." + methodName + "("
                 + Arrays.toString(parameters) + ")";
     }
+
 }
\ No newline at end of file
index 31297c0c6ca6d3067fbedc3ba7b9a063f86842c7..6e2602ff9c7b3ffccfbd620f719aac8c1cb5f2e2 100644 (file)
@@ -17,6 +17,7 @@ import java.io.Serializable;
 import java.io.StringWriter;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 import java.security.GeneralSecurityException;
 import java.text.CharacterIterator;
 import java.text.DateFormat;
@@ -807,8 +808,9 @@ public abstract class AbstractCommunicationManager implements Serializable {
             if (null != state) {
                 // encode and send shared state
                 try {
+                    // FIXME Use declared type
                     JSONArray stateJsonArray = JsonCodec.encode(state,
-                            application);
+                            state.getClass(), application);
                     sharedStates
                             .put(connector.getConnectorId(), stateJsonArray);
                 } catch (JSONException e) {
@@ -1368,43 +1370,6 @@ public abstract class AbstractCommunicationManager implements Serializable {
         return success;
     }
 
-    /**
-     * Helper class for parsing variable change RPC calls.
-     * 
-     * Note that variable changes still only support the old data types and
-     * partly use Vaadin 6 way of encoding of values. Other RPC method calls
-     * support more data types.
-     * 
-     * @since 7.0
-     */
-    private class VariableChange {
-        private final String name;
-        private final Object value;
-
-        public VariableChange(MethodInvocation invocation) throws JSONException {
-            name = (String) invocation.getParameters()[0];
-            value = invocation.getParameters()[1];
-        }
-
-        /**
-         * Returns the variable name for the modification.
-         * 
-         * @return variable name
-         */
-        public String getName() {
-            return name;
-        }
-
-        /**
-         * Returns the (parsed and converted) value of the updated variable.
-         * 
-         * @return variable value
-         */
-        public Object getValue() {
-            return value;
-        }
-    }
-
     /**
      * Processes a message burst received from the client.
      * 
@@ -1430,24 +1395,9 @@ public abstract class AbstractCommunicationManager implements Serializable {
         try {
             List<MethodInvocation> invocations = parseInvocations(burst);
 
-            // Perform the method invocations, grouping consecutive variable
-            // changes for the same Paintable.
-
-            // Combining of variable changes is currently needed to preserve the
-            // old semantics for any component that relies on them. If the
-            // support for legacy variable change events is removed, each call
-            // can be performed separately and thelogic here simplified.
-
             for (int i = 0; i < invocations.size(); i++) {
                 MethodInvocation invocation = invocations.get(i);
 
-                MethodInvocation nextInvocation = null;
-                if (i + 1 < invocations.size()) {
-                    nextInvocation = invocations.get(i + 1);
-                }
-
-                final String interfaceName = invocation.getInterfaceName();
-
                 final ClientConnector connector = getConnector(app,
                         invocation.getConnectorId());
 
@@ -1464,23 +1414,24 @@ public abstract class AbstractCommunicationManager implements Serializable {
 
                 if (!connector.isConnectorEnabled()) {
 
-                    if (ApplicationConnection.UPDATE_VARIABLE_INTERFACE
-                            .equals(interfaceName)) {
+                    if (invocation instanceof LegacyChangeVariablesInvocation) {
+                        LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation;
                         // TODO convert window close to a separate RPC call and
                         // handle above - not a variable change
-                        VariableChange change = new VariableChange(invocation);
 
                         // Handle special case where window-close is called
                         // after the window has been removed from the
                         // application or the application has closed
-                        if ("close".equals(change.getName())
-                                && Boolean.TRUE.equals(change.getValue())) {
+                        Map<String, Object> changes = legacyInvocation
+                                .getVariableChanges();
+                        if (changes.size() == 1 && changes.containsKey("close")
+                                && Boolean.TRUE.equals(changes.get("close"))) {
                             // Silently ignore this
                             continue;
                         }
                     }
 
-                    // Connector is disabled, log a warning and move the next
+                    // Connector is disabled, log a warning and move to the next
                     String msg = "Ignoring RPC call for disabled connector "
                             + connector.getClass().getName();
                     if (connector instanceof Component) {
@@ -1493,49 +1444,32 @@ public abstract class AbstractCommunicationManager implements Serializable {
                     continue;
                 }
 
-                if (!ApplicationConnection.UPDATE_VARIABLE_INTERFACE
-                        .equals(interfaceName)) {
-                    // handle other RPC calls than variable changes
-                    ServerRpcManager.applyInvocation(connector, invocation);
-                    continue;
-                }
-
-                // All code below is for legacy variable changes
-                final VariableOwner owner = (VariableOwner) connector;
-
-                VariableChange change = new VariableChange(invocation);
-
-                Map<String, Object> m = new HashMap<String, Object>();
-                m.put(change.getName(), change.getValue());
-                while (nextInvocation != null
-                        && invocation.getConnectorId().equals(
-                                nextInvocation.getConnectorId())
-                        && ApplicationConnection.UPDATE_VARIABLE_METHOD
-                                .equals(nextInvocation.getMethodName())) {
-                    i++;
-                    invocation = nextInvocation;
-                    change = new VariableChange(invocation);
-                    m.put(change.getName(), change.getValue());
-                    if (i + 1 < invocations.size()) {
-                        nextInvocation = invocations.get(i + 1);
-                    } else {
-                        nextInvocation = null;
-                    }
-                }
+                if (invocation instanceof ServerRPCMethodInvocation) {
+                    ServerRpcManager.applyInvocation(connector,
+                            (ServerRPCMethodInvocation) invocation);
+                } else {
 
-                try {
-                    changeVariables(source, owner, m);
-                } catch (Exception e) {
-                    Component errorComponent = null;
-                    if (owner instanceof Component) {
-                        errorComponent = (Component) owner;
-                    } else if (owner instanceof DragAndDropService) {
-                        if (m.get("dhowner") instanceof Component) {
-                            errorComponent = (Component) m.get("dhowner");
+                    // All code below is for legacy variable changes
+                    LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation;
+                    Map<String, Object> changes = legacyInvocation
+                            .getVariableChanges();
+                    try {
+                        changeVariables(source, (VariableOwner) connector,
+                                changes);
+                    } catch (Exception e) {
+                        Component errorComponent = null;
+                        if (connector instanceof Component) {
+                            errorComponent = (Component) connector;
+                        } else if (connector instanceof DragAndDropService) {
+                            Object dropHandlerOwner = changes.get("dhowner");
+                            if (dropHandlerOwner instanceof Component) {
+                                errorComponent = (Component) dropHandlerOwner;
+                            }
                         }
-                    }
-                    handleChangeVariablesError(app, errorComponent, e, m);
+                        handleChangeVariablesError(app, errorComponent, e,
+                                changes);
 
+                    }
                 }
             }
 
@@ -1564,25 +1498,94 @@ public abstract class AbstractCommunicationManager implements Serializable {
 
         ArrayList<MethodInvocation> invocations = new ArrayList<MethodInvocation>();
 
+        MethodInvocation previousInvocation = null;
         // parse JSON to MethodInvocations
         for (int i = 0; i < invocationsJson.length(); ++i) {
+
             JSONArray invocationJson = invocationsJson.getJSONArray(i);
-            String connectorId = invocationJson.getString(0);
-            String interfaceName = invocationJson.getString(1);
-            String methodName = invocationJson.getString(2);
-            JSONArray parametersJson = invocationJson.getJSONArray(3);
-            Object[] parameters = new Object[parametersJson.length()];
-            for (int j = 0; j < parametersJson.length(); ++j) {
-                parameters[j] = JsonCodec.decode(
-                        parametersJson.getJSONArray(j), application);
+
+            MethodInvocation invocation = parseInvocation(invocationJson,
+                    previousInvocation);
+            if (invocation != null) {
+                // Can be null iff the invocation was a legacy invocation and it
+                // was merged with the previous one
+                invocations.add(invocation);
+                previousInvocation = invocation;
             }
-            MethodInvocation invocation = new MethodInvocation(connectorId,
-                    interfaceName, methodName, parameters);
-            invocations.add(invocation);
         }
         return invocations;
     }
 
+    private MethodInvocation parseInvocation(JSONArray invocationJson,
+            MethodInvocation previousInvocation) throws JSONException {
+        String connectorId = invocationJson.getString(0);
+        String interfaceName = invocationJson.getString(1);
+        String methodName = invocationJson.getString(2);
+
+        JSONArray parametersJson = invocationJson.getJSONArray(3);
+
+        if (LegacyChangeVariablesInvocation.isLegacyVariableChange(
+                interfaceName, methodName)) {
+            if (!(previousInvocation instanceof LegacyChangeVariablesInvocation)) {
+                previousInvocation = null;
+            }
+
+            return parseLegacyChangeVariablesInvocation(connectorId,
+                    interfaceName, methodName,
+                    (LegacyChangeVariablesInvocation) previousInvocation,
+                    parametersJson);
+        } else {
+            return parseServerRpcInvocation(connectorId, interfaceName,
+                    methodName, parametersJson);
+        }
+
+    }
+
+    private LegacyChangeVariablesInvocation parseLegacyChangeVariablesInvocation(
+            String connectorId, String interfaceName, String methodName,
+            LegacyChangeVariablesInvocation previousInvocation,
+            JSONArray parametersJson) throws JSONException {
+        if (parametersJson.length() != 2) {
+            throw new JSONException(
+                    "Invalid parameters in legacy change variables call. Expected 2, was "
+                            + parametersJson.length());
+        }
+        String variableName = (String) JsonCodec
+                .decodeInternalType(String.class, true,
+                        parametersJson.getJSONArray(0), application);
+        Object value = JsonCodec.decodeInternalType(
+                parametersJson.getJSONArray(1), application);
+
+        if (previousInvocation != null
+                && previousInvocation.getConnectorId().equals(connectorId)) {
+            previousInvocation.setVariableChange(variableName, value);
+            return null;
+        } else {
+            return new LegacyChangeVariablesInvocation(connectorId,
+                    variableName, value);
+        }
+    }
+
+    private ServerRPCMethodInvocation parseServerRpcInvocation(
+            String connectorId, String interfaceName, String methodName,
+            JSONArray parametersJson) throws JSONException {
+        ServerRPCMethodInvocation invocation = new ServerRPCMethodInvocation(
+                connectorId, interfaceName, methodName, parametersJson.length());
+
+        Object[] parameters = new Object[parametersJson.length()];
+        Type[] declaredRpcMethodParameterTypes = invocation.getMethod()
+                .getGenericParameterTypes();
+
+        for (int j = 0; j < parametersJson.length(); ++j) {
+            JSONArray parameterJson = parametersJson.getJSONArray(j);
+            Type parameterType = declaredRpcMethodParameterTypes[j];
+            parameters[j] = JsonCodec.decodeInternalOrCustomType(parameterType,
+                    parameterJson, application);
+        }
+        invocation.setParameters(parameters);
+        return invocation;
+    }
+
     protected void changeVariables(Object source, final VariableOwner owner,
             Map<String, Object> m) {
         owner.changeVariables(source, m);
index 0d2b0c20823eb6688d8665f7a1198a5cc6cce308..375cce4161b9eb07987e869b8f60ed2833e7f43f 100644 (file)
@@ -117,7 +117,7 @@ public class JsonCodec implements Serializable {
                 application);
     }
 
-    public static <T> T decodeInternalOrCustomType(Type targetType,
+    public static Object decodeInternalOrCustomType(Type targetType,
             JSONArray valueAndType, Application application)
             throws JSONException {
         if (isInternalType(targetType)) {
@@ -128,7 +128,7 @@ public class JsonCodec implements Serializable {
         }
     }
 
-    public static <T> T decodeCustomType(Type targetType,
+    public static Object decodeCustomType(Type targetType,
             JSONArray valueAndType, Application application)
             throws JSONException {
         if (isInternalType(targetType)) {
@@ -137,7 +137,7 @@ public class JsonCodec implements Serializable {
         }
         String transportType = getCustomTransportType(getClassForType(targetType));
         String encodedTransportType = valueAndType.getString(0);
-        if (!encodedTransportType.equals(transportType)) {
+        if (!transportTypesCompatible(encodedTransportType, transportType)) {
             throw new JSONException("Expected a value of type " + transportType
                     + ", received " + encodedTransportType);
         }
@@ -171,47 +171,49 @@ public class JsonCodec implements Serializable {
      * @return
      * @throws JSONException
      */
-    public static <T> T decodeInternalType(Type targetType,
+    public static Object decodeInternalType(Type targetType,
             boolean restrictToInternalTypes, JSONArray valueAndType,
             Application application) throws JSONException {
+        String encodedTransportType = valueAndType.getString(0);
         if (!isInternalType(targetType)) {
-            throw new JSONException("Cannot decode internal type. Type "
-                    + targetType + " is not supported.");
+            throw new JSONException("Type " + targetType
+                    + " is not a supported internal type.");
         }
         String transportType = getInternalTransportType(targetType);
-        String encodedTransportType = valueAndType.getString(0);
-        if (!encodedTransportType.equals(transportType)) {
-            throw new JSONException("Expected a value of type " + transportType
-                    + ", received " + encodedTransportType);
+        if (!transportTypesCompatible(encodedTransportType, transportType)) {
+            throw new JSONException("Expected a value of type " + targetType
+                    + ", received " + getType(encodedTransportType));
         }
 
         Object encodedJsonValue = valueAndType.get(1);
 
+        if (JsonEncoder.VTYPE_NULL.equals(encodedTransportType)) {
+            return null;
+        }
         // Collections
         if (JsonEncoder.VTYPE_LIST.equals(transportType)) {
-            return (T) decodeList(targetType, restrictToInternalTypes,
+            return decodeList(targetType, restrictToInternalTypes,
                     (JSONArray) encodedJsonValue, application);
         } else if (JsonEncoder.VTYPE_SET.equals(transportType)) {
-            return (T) decodeSet(targetType, restrictToInternalTypes,
+            return decodeSet(targetType, restrictToInternalTypes,
                     (JSONArray) encodedJsonValue, application);
         } else if (JsonEncoder.VTYPE_MAP_CONNECTOR.equals(transportType)) {
-            return (T) decodeConnectorToObjectMap(targetType,
+            return decodeConnectorToObjectMap(targetType,
                     restrictToInternalTypes, (JSONObject) encodedJsonValue,
                     application);
         } else if (JsonEncoder.VTYPE_MAP.equals(transportType)) {
-            return (T) decodeStringToObjectMap(targetType,
-                    restrictToInternalTypes, (JSONObject) encodedJsonValue,
-                    application);
+            return decodeStringToObjectMap(targetType, restrictToInternalTypes,
+                    (JSONObject) encodedJsonValue, application);
         }
 
         // Arrays
         if (JsonEncoder.VTYPE_ARRAY.equals(transportType)) {
 
-            return (T) decodeObjectArray(targetType,
-                    (JSONArray) encodedJsonValue, application);
+            return decodeObjectArray(targetType, (JSONArray) encodedJsonValue,
+                    application);
 
         } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(transportType)) {
-            return (T) decodeStringArray((JSONArray) encodedJsonValue);
+            return decodeStringArray((JSONArray) encodedJsonValue);
         }
 
         // Special Vaadin types
@@ -219,30 +221,43 @@ public class JsonCodec implements Serializable {
         String stringValue = String.valueOf(encodedJsonValue);
 
         if (JsonEncoder.VTYPE_CONNECTOR.equals(transportType)) {
-            return (T) application.getConnector(stringValue);
+            return application.getConnector(stringValue);
         }
 
         // Standard Java types
 
         if (JsonEncoder.VTYPE_STRING.equals(transportType)) {
-            return (T) stringValue;
+            return stringValue;
         } else if (JsonEncoder.VTYPE_INTEGER.equals(transportType)) {
-            return (T) Integer.valueOf(stringValue);
+            return Integer.valueOf(stringValue);
         } else if (JsonEncoder.VTYPE_LONG.equals(transportType)) {
-            return (T) Long.valueOf(stringValue);
+            return Long.valueOf(stringValue);
         } else if (JsonEncoder.VTYPE_FLOAT.equals(transportType)) {
-            return (T) Float.valueOf(stringValue);
+            return Float.valueOf(stringValue);
         } else if (JsonEncoder.VTYPE_DOUBLE.equals(transportType)) {
-            return (T) Double.valueOf(stringValue);
+            return Double.valueOf(stringValue);
         } else if (JsonEncoder.VTYPE_BOOLEAN.equals(transportType)) {
-            return (T) Boolean.valueOf(stringValue);
-        } else if (JsonEncoder.VTYPE_NULL.equals(transportType)) {
-            return null;
+            return Boolean.valueOf(stringValue);
         }
 
         throw new JSONException("Unknown type " + transportType);
     }
 
+    private static boolean transportTypesCompatible(
+            String encodedTransportType, String transportType) {
+        if (encodedTransportType == null) {
+            return false;
+        }
+        if (encodedTransportType.equals(transportType)) {
+            return true;
+        }
+        if (encodedTransportType.equals(JsonEncoder.VTYPE_NULL)) {
+            return true;
+        }
+
+        return false;
+    }
+
     @Deprecated
     private static Map<String, Object> decodeStringToObjectMap(Type targetType,
             boolean restrictToInternalTypes, JSONObject jsonMap,
@@ -252,54 +267,60 @@ public class JsonCodec implements Serializable {
         while (it.hasNext()) {
             String key = it.next();
             JSONArray encodedValueAndType = jsonMap.getJSONArray(key);
-            Object decodedChild;
-            if (!restrictToInternalTypes
-                    && targetType instanceof ParameterizedType) {
-                Type mapValueType = ((ParameterizedType) targetType)
-                        .getActualTypeArguments()[1];
-                // Only decode the given type
-                decodedChild = decodeInternalOrCustomType(mapValueType,
-                        encodedValueAndType, application);
-            } else {
-                // Only internal types when not enforcing a given type to avoid
-                // security issues
-                decodedChild = decodeInternalType(encodedValueAndType,
-                        application);
-            }
+            Object decodedChild = decodeChild(targetType,
+                    restrictToInternalTypes, 1, encodedValueAndType,
+                    application);
             map.put(key, decodedChild);
         }
         return map;
     }
 
     @Deprecated
-    private static Object decodeConnectorToObjectMap(Type targetType,
-            boolean restrictToInternalTypes, JSONObject jsonMap,
-            Application application) throws JSONException {
+    private static Map<Connector, Object> decodeConnectorToObjectMap(
+            Type targetType, boolean restrictToInternalTypes,
+            JSONObject jsonMap, Application application) throws JSONException {
         HashMap<Connector, Object> map = new HashMap<Connector, Object>();
         Iterator<String> it = jsonMap.keys();
         while (it.hasNext()) {
             String connectorId = it.next();
             Connector connector = application.getConnector(connectorId);
             JSONArray encodedValueAndType = jsonMap.getJSONArray(connectorId);
-            Object decodedChild;
-            if (!restrictToInternalTypes
-                    && targetType instanceof ParameterizedType) {
-                Type mapValueType = ((ParameterizedType) targetType)
-                        .getActualTypeArguments()[1];
-                // Only decode the given type
-                decodedChild = decodeInternalOrCustomType(mapValueType,
-                        encodedValueAndType, application);
-            } else {
-                // Only internal types when not enforcing a given type to avoid
-                // security issues
-                decodedChild = decodeInternalType(encodedValueAndType,
-                        application);
-            }
+            Object decodedChild = decodeChild(targetType,
+                    restrictToInternalTypes, 1, encodedValueAndType,
+                    application);
             map.put(connector, decodedChild);
         }
         return map;
     }
 
+    /**
+     * @param targetType
+     * @param restrictToInternalTypes
+     * @param typeIndex
+     *            The index of a generic type to use to define the child type
+     *            that should be decoded
+     * @param encodedValueAndType
+     * @param application
+     * @return
+     * @throws JSONException
+     */
+    private static Object decodeChild(Type targetType,
+            boolean restrictToInternalTypes, int typeIndex,
+            JSONArray encodedValueAndType, Application application)
+            throws JSONException {
+        if (!restrictToInternalTypes && targetType instanceof ParameterizedType) {
+            Type childType = ((ParameterizedType) targetType)
+                    .getActualTypeArguments()[typeIndex];
+            // Only decode the given type
+            return decodeInternalOrCustomType(childType, encodedValueAndType,
+                    application);
+        } else {
+            // Only internal types when not enforcing a given type to avoid
+            // security issues
+            return decodeInternalType(encodedValueAndType, application);
+        }
+    }
+
     private static String[] decodeStringArray(JSONArray jsonArray)
             throws JSONException {
         int length = jsonArray.length();
@@ -322,20 +343,10 @@ public class JsonCodec implements Serializable {
         List<Object> list = new ArrayList<Object>();
         for (int i = 0; i < jsonArray.length(); ++i) {
             // each entry always has two elements: type and value
-            JSONArray entryArray = jsonArray.getJSONArray(i);
-            Object decodedChild;
-            if (!restrictToInternalTypes
-                    && targetType instanceof ParameterizedType) {
-                // Only decode the given type
-                Type childType = ((ParameterizedType) targetType)
-                        .getActualTypeArguments()[0];
-                decodedChild = decodeInternalOrCustomType(childType,
-                        entryArray, application);
-            } else {
-                // Only internal types when not enforcing a given type to avoid
-                // security issues
-                decodedChild = decodeInternalType(entryArray, application);
-            }
+            JSONArray encodedValueAndType = jsonArray.getJSONArray(i);
+            Object decodedChild = decodeChild(targetType,
+                    restrictToInternalTypes, 0, encodedValueAndType,
+                    application);
             list.add(decodedChild);
         }
         return list;
@@ -368,7 +379,7 @@ public class JsonCodec implements Serializable {
         return pd.getWriteMethod().getName().substring(3);
     }
 
-    private static <T> T decodeObject(Type targetType,
+    private static Object decodeObject(Type targetType,
             JSONObject serializedObject, Application application)
             throws JSONException {
 
@@ -391,7 +402,7 @@ public class JsonCodec implements Serializable {
                 pd.getWriteMethod().invoke(decodedObject, decodedFieldValue);
             }
 
-            return (T) decodedObject;
+            return decodedObject;
         } catch (IllegalArgumentException e) {
             throw new JSONException(e);
         } catch (IllegalAccessException e) {
@@ -566,7 +577,7 @@ public class JsonCodec implements Serializable {
      * @throws JSONException
      */
     private static String getInternalTransportType(Type valueType) {
-        return typeToTransportType.get(valueType);
+        return typeToTransportType.get(getClassForType(valueType));
     }
 
     private static String getCustomTransportType(Class<?> targetType) {
diff --git a/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java b/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java
new file mode 100644 (file)
index 0000000..42fa3ab
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.server;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
+
+public class LegacyChangeVariablesInvocation extends MethodInvocation {
+    private Map<String, Object> variableChanges = new HashMap<String, Object>();
+
+    public LegacyChangeVariablesInvocation(String connectorId,
+            String variableName, Object value) {
+        super(connectorId, ApplicationConnection.UPDATE_VARIABLE_INTERFACE,
+                ApplicationConnection.UPDATE_VARIABLE_METHOD);
+        setVariableChange(variableName, value);
+    }
+
+    public static boolean isLegacyVariableChange(String interfaceName,
+            String methodName) {
+        return ApplicationConnection.UPDATE_VARIABLE_METHOD
+                .equals(interfaceName)
+                && ApplicationConnection.UPDATE_VARIABLE_METHOD
+                        .equals(methodName);
+    }
+
+    public void setVariableChange(String name, Object value) {
+        variableChanges.put(name, value);
+    }
+
+    public Map<String, Object> getVariableChanges() {
+        return variableChanges;
+    }
+
+}
index 5fcfda50a51d94ab743e41e0127382a9066cc6ba..a629447069a3ebe6191009fe87f5af987e4a6eaf 100644 (file)
@@ -6,8 +6,6 @@ package com.vaadin.terminal.gwt.server;
 
 import java.io.Serializable;
 
-import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
-
 /**
  * Server side RPC manager that can invoke methods based on RPC calls received
  * from the client.
@@ -15,5 +13,5 @@ import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
  * @since 7.0
  */
 public interface RpcManager extends Serializable {
-    public void applyInvocation(MethodInvocation invocation);
+    public void applyInvocation(ServerRPCMethodInvocation invocation);
 }
diff --git a/src/com/vaadin/terminal/gwt/server/ServerRPCMethodInvocation.java b/src/com/vaadin/terminal/gwt/server/ServerRPCMethodInvocation.java
new file mode 100644 (file)
index 0000000..6afb549
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.server;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
+import com.vaadin.terminal.gwt.client.communication.ServerRpc;
+
+public class ServerRPCMethodInvocation extends MethodInvocation {
+
+    private static final Map<String, Method> invocationMethodCache = new ConcurrentHashMap<String, Method>(
+            128, 0.75f, 1);
+
+    private final Method method;
+
+    private Class<? extends ServerRpc> interfaceClass;
+
+    public ServerRPCMethodInvocation(String connectorId, String interfaceName,
+            String methodName, int parameterCount) {
+        super(connectorId, interfaceName, methodName);
+
+        interfaceClass = findClass();
+        method = findInvocationMethod(interfaceClass, methodName,
+                parameterCount);
+    }
+
+    private Class<? extends ServerRpc> findClass() {
+        try {
+            Class<?> rpcInterface = Class.forName(getInterfaceName());
+            if (!ServerRpc.class.isAssignableFrom(rpcInterface)) {
+                throw new IllegalArgumentException("The interface "
+                        + getInterfaceName() + "is not a server RPC interface.");
+            }
+            return (Class<? extends ServerRpc>) rpcInterface;
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException("The server RPC interface "
+                    + getInterfaceName() + " could not be found", e);
+        } finally {
+
+        }
+    }
+
+    public Class<? extends ServerRpc> getInterfaceClass() {
+        return interfaceClass;
+    }
+
+    public Method getMethod() {
+        return method;
+    }
+
+    /**
+     * Tries to find the method from the cache or alternatively by invoking
+     * {@link #doFindInvocationMethod(Class, String, int)} and updating the
+     * cache.
+     * 
+     * @param targetType
+     * @param methodName
+     * @param parameterCount
+     * @return
+     */
+    private Method findInvocationMethod(Class<?> targetType, String methodName,
+            int parameterCount) {
+        // TODO currently only using method name and number of parameters as the
+        // signature
+        String signature = targetType.getName() + "." + methodName + "("
+                + parameterCount;
+        Method invocationMethod = invocationMethodCache.get(signature);
+
+        if (invocationMethod == null) {
+            invocationMethod = doFindInvocationMethod(targetType, methodName,
+                    parameterCount);
+
+            if (invocationMethod != null) {
+                invocationMethodCache.put(signature, invocationMethod);
+            }
+        }
+
+        return invocationMethod;
+    }
+
+    /**
+     * Tries to find the method from the class by looping through available
+     * methods.
+     * 
+     * @param targetType
+     * @param methodName
+     * @param parameterCount
+     * @return
+     */
+    private Method doFindInvocationMethod(Class<?> targetType,
+            String methodName, int parameterCount) {
+        Method[] methods = targetType.getMethods();
+        for (Method method : methods) {
+            Class<?>[] parameterTypes = method.getParameterTypes();
+            if (method.getName().equals(methodName)
+                    && parameterTypes.length == parameterCount) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+}
index 288e0bf9330f17fc94d54d475ade94ae7f0a6db1..025af7d61d51c9f3b4e3d683f5db8b36a1cd4414 100644 (file)
@@ -8,12 +8,10 @@ import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.vaadin.terminal.gwt.client.Connector;
-import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
 
 /**
  * Server side RPC manager that handles RPC calls coming from the client.
@@ -29,9 +27,6 @@ public class ServerRpcManager<T> implements RpcManager {
     private final T implementation;
     private final Class<T> rpcInterface;
 
-    private static final Map<String, Method> invocationMethodCache = new ConcurrentHashMap<String, Method>(
-            128, 0.75f, 1);
-
     private static final Map<Class<?>, Class<?>> boxedTypes = new HashMap<Class<?>, Class<?>>();
     static {
         try {
@@ -73,26 +68,19 @@ public class ServerRpcManager<T> implements RpcManager {
      *            method invocation to perform
      */
     public static void applyInvocation(RpcTarget target,
-            MethodInvocation invocation) {
-        try {
-            Class<?> rpcInterfaceClass = Class.forName(invocation
-                    .getInterfaceName());
-            RpcManager manager = target.getRpcManager(rpcInterfaceClass);
-            if (manager != null) {
-                manager.applyInvocation(invocation);
-            } else {
-                getLogger()
-                        .log(Level.WARNING,
-                                "RPC call received for RpcTarget "
-                                        + target.getClass().getName()
-                                        + " ("
-                                        + invocation.getConnectorId()
-                                        + ") but the target has not registered any RPC interfaces");
-            }
-        } catch (ClassNotFoundException e) {
-            throw new RuntimeException("Class for RPC interface "
-                    + invocation.getInterfaceName() + " of the target "
-                    + target + " could not be found.");
+            ServerRPCMethodInvocation invocation) {
+        RpcManager manager = target.getRpcManager(invocation
+                .getInterfaceClass());
+        if (manager != null) {
+            manager.applyInvocation(invocation);
+        } else {
+            getLogger()
+                    .log(Level.WARNING,
+                            "RPC call received for RpcTarget "
+                                    + target.getClass().getName()
+                                    + " ("
+                                    + invocation.getConnectorId()
+                                    + ") but the target has not registered any RPC interfaces");
         }
     }
 
@@ -121,21 +109,11 @@ public class ServerRpcManager<T> implements RpcManager {
      * @param invocation
      *            method invocation to perform
      */
-    public void applyInvocation(MethodInvocation invocation) {
-        String methodName = invocation.getMethodName();
-        // here, we already know that the interface is an rpcInterface
-        Object[] arguments = invocation.getParameters();
-
-        Method method = findInvocationMethod(rpcInterface, methodName,
-                arguments.length);
-        if (method == null) {
-            throw new RuntimeException(implementation + " does not contain "
-                    + rpcInterface.getName() + "." + methodName + " with "
-                    + arguments.length + " parameters");
-        }
-
+    public void applyInvocation(ServerRPCMethodInvocation invocation) {
+        Method method = invocation.getMethod();
         Class<?>[] parameterTypes = method.getParameterTypes();
         Object[] args = new Object[parameterTypes.length];
+        Object[] arguments = invocation.getParameters();
         for (int i = 0; i < args.length; i++) {
             // no conversion needed for basic cases
             // Class<?> type = parameterTypes[i];
@@ -147,41 +125,10 @@ public class ServerRpcManager<T> implements RpcManager {
         try {
             method.invoke(implementation, args);
         } catch (Exception e) {
-            throw new RuntimeException(methodName, e);
-        }
-    }
-
-    private Method findInvocationMethod(Class<?> targetType, String methodName,
-            int parameterCount) {
-        // TODO currently only using method name and number of parameters as the
-        // signature
-        String signature = targetType.getName() + "." + methodName + "("
-                + parameterCount;
-        Method invocationMethod = invocationMethodCache.get(signature);
-
-        if (invocationMethod == null) {
-            invocationMethod = doFindInvocationMethod(targetType, methodName,
-                    parameterCount);
-
-            if (invocationMethod != null) {
-                invocationMethodCache.put(signature, invocationMethod);
-            }
-        }
-
-        return invocationMethod;
-    }
-
-    private Method doFindInvocationMethod(Class<?> targetType,
-            String methodName, int parameterCount) {
-        Method[] methods = targetType.getMethods();
-        for (Method method : methods) {
-            Class<?>[] parameterTypes = method.getParameterTypes();
-            if (method.getName().equals(methodName)
-                    && parameterTypes.length == parameterCount) {
-                return method;
-            }
+            throw new RuntimeException("Unable to invoke method "
+                    + invocation.getMethodName() + " in "
+                    + invocation.getInterfaceName(), e);
         }
-        return null;
     }
 
     private static Logger getLogger() {