package fr.lteconsulting.hexa.server.rpc; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.HashMap; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import fr.lteconsulting.hexa.server.tools.Trace; import fr.lteconsulting.hexa.shared.rpc.ListInteger; class ServiceDescription { String name; String checksum; Object delegate; String[] methodShortcuts; // cache methods informations private final HashMap<String, MethodInfo> methodsCache = new HashMap<String, MethodInfo>(); private static class MethodInfo { MethodInfo( Method method ) { this.method = method; paramTypes = method.getParameterTypes(); } Method method; Class<?>[] paramTypes; } public ServiceDescription( String name, String checksum, Object delegate, String[] methodShortcuts ) { this.name = name; this.checksum = checksum; this.delegate = delegate; this.methodShortcuts = methodShortcuts; } private MethodInfo findMethod( String methodName ) { MethodInfo result = methodsCache.get( methodName ); if( result != null ) return result; Method[] methods = delegate.getClass().getMethods(); for( int i = 0; i < methods.length; i++ ) { Method method = methods[i]; if( method.getName().equals( methodName ) ) { MethodInfo methodInfo = new MethodInfo( method ); methodsCache.put( methodName, methodInfo ); return methodInfo; } } return null; } public Object call( String method, JsonArray parameters ) { // Try parsing a numeric encoded value of the called method try { method = methodShortcuts[Integer.parseInt( method )]; } catch( NumberFormatException badFormat ) { } Trace.it( "Calling method " + method ); MethodInfo jmethod = findMethod( method ); if( jmethod == null ) { throw new RuntimeException( "Called method not found in delegate of class " + delegate.getClass().getName() ); } Trace.it( "Deserialize parameters" ); // Deserialize the parameters Class<?>[] paramTypes = jmethod.paramTypes; if( !(parameters == null && paramTypes.length == 0) && parameters.size() != paramTypes.length ) throw new InvalidParameterException( "parameters.size()!=paramTypes.length" ); Object[] jparams = new Object[paramTypes.length]; for( int i = 0; i < paramTypes.length; i++ ) { Trace.it( "Param " + i ); Class<?> classType = paramTypes[i]; JsonElement p = parameters.get( i ); jparams[i] = deserializeParameters( classType, p ); } // Call the delegate try { Trace.it( "Real call..." ); Object res = jmethod.method.invoke( delegate, jparams ); Trace.it( "Ok" ); return res; } catch( Exception e ) { Trace.it( "Failed with: " + e.getClass().getName() ); Trace.throwable( e.getCause() ); throw new RuntimeException( e ); } } private Object deserializeParameters( Class<?> classType, JsonElement p ) { if( p == null ) return null; if( classType == String.class ) return p.getAsString(); else if( classType == int.class ) return p.getAsInt(); else if( classType == Integer.class ) return new Integer( p.getAsInt() ); else if( classType == ListInteger.class ) { JsonArray jsonArray = p.getAsJsonArray(); int size = jsonArray.size(); ListInteger res = new ListInteger(); for( int i = 0; i < size; i++ ) res.add( (Integer) deserializeParameters( Integer.class, jsonArray.get( i ) ) ); return res; } else if( classType.isArray() ) { JsonArray jsonArray = p.getAsJsonArray(); int size = jsonArray.size(); Class<?> componentClass = classType.getComponentType(); if( componentClass.isPrimitive() ) { if( componentClass == int.class ) { int[] res = new int[size]; for( int i = 0; i < size; i++ ) res[i] = jsonArray.get( i ).getAsInt(); return res; } else if( componentClass == String.class ) { String[] res = new String[size]; for( int i = 0; i < size; i++ ) res[i] = jsonArray.get( i ).getAsString(); return res; } } Object res = Array.newInstance( componentClass, size ); for( int i = 0; i < size; i++ ) Array.set( res, i, deserializeParameters( componentClass, jsonArray.get( i ) ) ); return res; } else if( classType == ArrayList.class ) { throw new RuntimeException( "Deserialization of an ArrayList<?>, please use one of the wrapping types like ListInteger...)" ); } else { throw new RuntimeException( "Unknown deserialization of parameter for class " + classType.getName() + " json element is " + p.toString() ); } } }