package greencode.jscript.dom; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import greencode.exception.OperationNotAllowedException; import greencode.http.enumeration.RequestMethod; import greencode.jscript.DOM; import greencode.jscript.dom.elements.custom.ContainerElement; import greencode.jscript.dom.form.annotation.Name; import greencode.jscript.dom.function.implementation.Function; import greencode.jscript.dom.window.annotation.Form; import greencode.kernel.GreenCodeConfig; import greencode.kernel.GreenContext; import greencode.util.ClassUtils; import greencode.util.GenericReflection; import greencode.util.LogMessage; public final class FunctionHandle { private static final transient Map<Class<?>, Method> methodsInitCached = new HashMap<Class<?>, Method>(); private final transient GreenContext context = GreenContext.getInstance(); private final Integer cid = context.getRequest().getConversationId(), viewId = context.getRequest().getViewSession().getId(); private String url, formName, requestMethod = GreenCodeConfig.Server.Request.methodType.toUpperCase(); private JsonElement methodParameters; private JsonObject[] args; private JsonObject requestParameters; public FunctionHandle(String commandName, Object... parameters) { this.url = '#'+commandName; if(parameters.length > 0) this.methodParameters = context.gsonInstance.toJsonTree(parameters); } public FunctionHandle(Function o) { this.setUrl(o); } public FunctionHandle(String method) { this.setUrl(context.currentWindow().getClass(), method); } public FunctionHandle(String method, Class<? extends DOM>... args) { this.setUrl(context.currentWindow().getClass(), method, args); } public FunctionHandle(Class<? extends Window> controller, String method) { this.setUrl(controller, method); } public FunctionHandle(Class<? extends Window> controller, String method, Class<? extends DOM>... args) { this.setUrl(controller, method, args); } public RequestMethod getRequestMethod() { return RequestMethod.valueOf(requestMethod); } public void setRequestMethod(RequestMethod requestMethod) { this.requestMethod = requestMethod.name(); } public void registerRequestParameter(String parameter, String value) { if(this.requestParameters == null) { this.requestParameters = new JsonObject(); } this.requestParameters.addProperty(parameter, value); } private static final Map<Integer, JsonObject[]> argsCached = new HashMap<Integer, JsonObject[]>(); private FunctionHandle setArguments(final Class<?>... args) { if(args.length > 0) { int hashCode = Arrays.hashCode(args); if((this.args = argsCached.get(hashCode)) != null) return this; this.args = new JsonObject[args.length]; for (int i = -1; ++i < args.length;) { Class<?> clazz = args[i]; if(!clazz.equals(GreenContext.class) && !ClassUtils.isParent(clazz, DOM.class)) throw new RuntimeException(LogMessage.getMessage("green-0035", clazz.getSimpleName())); JsonObject json = new JsonObject(); if(!clazz.equals(GreenContext.class)) { if(ClassUtils.isParent(clazz, ContainerElement.class)) clazz = ContainerElement.class; else if(ClassUtils.isParent(clazz, Element.class)) { json.addProperty("castTo", clazz.getName()); clazz = Element.class; } else { JsonArray fieldsName = new JsonArray(); json.add("fields", fieldsName); final Class<?>[] classes = ClassUtils.getParents(clazz, DOM.class); Class<?> parent = clazz; int j = -1; do { Field[] fields = GenericReflection.getDeclaredFields(parent); for (Field f : fields) { if(!Modifier.isTransient(f.getModifiers())) fieldsName.add(context.gsonInstance.toJsonTree(f.getName())); } } while(++j < classes.length && (parent = classes[j]) != null); } } json.addProperty("className", clazz.getName()); this.args[i] = json; } argsCached.put(Arrays.hashCode(args), this.args); } return this; } private void setUrl(Function o) { if(o instanceof DOM) throw new OperationNotAllowedException(); Class<?> _class = o.getClass(); Method method; if((method = methodsInitCached.get(_class)) != null) setArguments(method.getParameterTypes()); else { Method[] methods = _class.getMethods(); for (Method m : methods) { if(m.getName().equals("init")) { methodsInitCached.put(_class, method = m); setArguments(m.getParameterTypes()); break; } } } checkMethodAnnotation(method); int hashcode = o.hashCode(); greencode.jscript.dom.$Window.getRegisteredFunctions(context.currentWindow()).put(hashcode, o); this.setUrl(context.currentWindow().getClass().getSimpleName()+"$"+hashcode); } private void setUrl(Class<? extends Window> windowClass, String methodName, Class<? extends DOM>... args) { try { Method method; Class<?>[] _args; try { _args = args; method = GenericReflection.getMethod(windowClass, methodName, _args); } catch (Exception e) { _args = new Class<?>[args.length+1]; _args[0] = GreenContext.class; for (int i = 0; ++i < _args.length;) _args[i] = args[i-1]; method = GenericReflection.getMethod(windowClass, methodName, _args); } setArguments(_args); checkMethodAnnotation(method); this.setUrl(windowClass.getSimpleName()+"@"+methodName); } catch (Exception e) { throw new RuntimeException(e); } } private void checkMethodAnnotation(Method method) { if(method.isAnnotationPresent(Form.class)) { Class<? extends greencode.jscript.dom.Form> form = method.getAnnotation(Form.class).value(); Field[] fields = greencode.jscript.dom.$Container.processFields(form); if(fields != null && fields.length > 0) { this.formName = form.getAnnotation(Name.class).value(); } } } private void setUrl(String url) { this.url = (context != null ? greencode.kernel.$GreenContext.getContextPath() : "") +"/"+url; } public static void destroy(Window window, Function anonymousClass) { window.functions.remove(anonymousClass.hashCode()); } }