package org.jwebsocket.plugins.rpc; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.List; import org.jwebsocket.plugins.rpc.util.ListConverter; import org.jwebsocket.plugins.rpc.util.MethodMatcherConversionException; import org.jwebsocket.token.Token; @SuppressWarnings("rawtypes") public class MethodMatcher { private Object[] mMethodParameters ; private Method mMethod; public MethodMatcher (Method aMethod) { mMethod = aMethod; } /** * Should only be used after isMethodMatchingAgainstParameter() is invoked and returns true. * @return the list of the parameters you need to invoke the method. */ public Object[] getMethodParameters() { return mMethodParameters; } /** * Match the given parameters again the method * If the parameters match, cast and save the parameters in mMethodParameters object. * Once this method is called (and if true), getMethodParameters() will contains all the correct parameters you need to invoke the method. * @param mMethod * @param aArgs * @return true if the method is matching, false otherwise. */ public boolean isMethodMatchingAgainstParameter (List aArgs) { Class[] lParametersType = mMethod.getParameterTypes(); if (aArgs == null) { if (lParametersType.length == 0) { mMethodParameters = null ; return true ; } return false ; } mMethodParameters = new Object[lParametersType.length]; // We are looking for a method with the same number of parameters if (getNumberOfValidParameters(lParametersType) == aArgs.size()) { // We make sure the types of the method match try { int k = -1; for (int j = 0; j < lParametersType.length; j++) { k++; Class lParameterType = lParametersType[j]; // Try to guess the object type. // Only support primitive type+wrapper, String, List and Token. // String and Token //TODO: with the new Tokens, we don't need anymore to check every arguments. Just need to take care of Float/Double and specific types. if (lParameterType == String.class) { mMethodParameters[j] = (String) aArgs.get(k); } else if (lParameterType == Token.class) { mMethodParameters[j] = (Token) aArgs.get(k); } // Special support for primitive type else if (lParameterType == int.class) { mMethodParameters[j] = (Integer) aArgs.get(k); } else if (lParameterType == boolean.class) { mMethodParameters[j] = (Boolean) aArgs.get(k); } else if (lParameterType == double.class) { mMethodParameters[j] = (Double) aArgs.get(k); } // Wrappers of primitive types else if (lParameterType == Integer.class) { mMethodParameters[j] = (Integer) aArgs.get(k); } else if (lParameterType == Boolean.class) { mMethodParameters[j] = (Boolean) aArgs.get(k); } else if (lParameterType == Double.class) { mMethodParameters[j] = (Double) aArgs.get(k); } else if (lParameterType == List.class) { // try to guess which type of object should be on the List: Type genericParameterType = mMethod.getGenericParameterTypes()[j]; mMethodParameters[j] = ListConverter.convert((List) aArgs.get(k), genericParameterType); } else if (specificMatching(lParameterType, j)) { k--; } // any other object are *not* supported ! else{ // if (mLog.isDebugEnabled()) { // mLog.debug("Can't extract an object with type '" + lParameterType.getName() + "' in a Token Object"); // } throw new MethodMatcherConversionException("Can't extract an object whith type '" + lParameterType.getName() + "' in a Token Object"); } } //If no exception has been thrown, so the method mat //We return the list of lArgs ready for the request. return true; } catch (Exception e) { //TODO: shouldn't catch a global Exception e here. Need to change it in the ListConverter class // That's the wrong method. return false; } } return false; } /** * @return the number of valid paramters inside a method. * Specific parameter can be ignored here. (For instance, a WebSocketConnector is ignored in ServerMethodMatcher) */ protected int getNumberOfValidParameters (Class[] aListOfParametersType) { return aListOfParametersType.length; } /** * Set the parameter "aIndice" to aParameter (in the list of parameter used to invoke the method) * @param aIndice * @param aParameter */ protected void setMethodParameters (int aIndice, Object aParameter) { mMethodParameters[aIndice] = aParameter ; } /** * Specific method if you need to add a specific matching type for the server or a client. * For instance, specificMatching is redefined in ServerMethodMatcher to detects if a WebSocketConnector is on of the parameters. * @param lParameterType * @return */ protected boolean specificMatching(Class lParameterType, int aIndice) { return false; } }