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() {
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
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;
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) {
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.
*
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());
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) {
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);
+ }
}
}
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);
application);
}
- public static <T> T decodeInternalOrCustomType(Type targetType,
+ public static Object decodeInternalOrCustomType(Type targetType,
JSONArray valueAndType, Application application)
throws JSONException {
if (isInternalType(targetType)) {
}
}
- public static <T> T decodeCustomType(Type targetType,
+ public static Object decodeCustomType(Type targetType,
JSONArray valueAndType, Application application)
throws JSONException {
if (isInternalType(targetType)) {
}
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);
}
* @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
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,
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();
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;
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 {
pd.getWriteMethod().invoke(decodedObject, decodedFieldValue);
}
- return (T) decodedObject;
+ return decodedObject;
} catch (IllegalArgumentException e) {
throw new JSONException(e);
} catch (IllegalAccessException e) {
* @throws JSONException
*/
private static String getInternalTransportType(Type valueType) {
- return typeToTransportType.get(valueType);
+ return typeToTransportType.get(getClassForType(valueType));
}
private static String getCustomTransportType(Class<?> targetType) {
--- /dev/null
+/*
+@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;
+ }
+
+}
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.
* @since 7.0
*/
public interface RpcManager extends Serializable {
- public void applyInvocation(MethodInvocation invocation);
+ public void applyInvocation(ServerRPCMethodInvocation invocation);
}
--- /dev/null
+/*
+@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;
+ }
+
+}
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.
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 {
* 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");
}
}
* @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];
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() {