/** * Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jfinal.aop; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import com.jfinal.core.Action; import com.jfinal.core.Controller; import net.sf.cglib.proxy.MethodProxy; /** * Invocation is used to invoke the interceptors and the target method */ @SuppressWarnings("unchecked") public class Invocation { private Action action; private static final Object[] NULL_ARGS = new Object[0]; // Prevent new Object[0] by jvm for paras of action invocation. boolean useInjectTarget; private Object target; private Method method; private Object[] args; private MethodProxy methodProxy; private Interceptor[] inters; private Object returnValue = null; private int index = 0; // InvocationWrapper need this constructor protected Invocation() { this.action = null; } public Invocation(Action action, Controller controller) { this.action = action; this.inters = action.getInterceptors(); this.target = controller; this.args = NULL_ARGS; } public Invocation(Object target, Method method, Object[] args, MethodProxy methodProxy, Interceptor[] inters) { this.action = null; this.target = target; this.method = method; this.args = args; this.methodProxy = methodProxy; this.inters = inters; } public void invoke() { if (index < inters.length) { inters[index++].intercept(this); } else if (index++ == inters.length) { // index++ ensure invoke action only one time try { // Invoke the action if (action != null) { returnValue = action.getMethod().invoke(target, args); } // Invoke the method else { // if (!Modifier.isAbstract(method.getModifiers())) // returnValue = methodProxy.invokeSuper(target, args); if (useInjectTarget) returnValue = methodProxy.invoke(target, args); else returnValue = methodProxy.invokeSuper(target, args); } } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); throw t instanceof RuntimeException ? (RuntimeException)t : new RuntimeException(e); } catch (RuntimeException e) { throw e; } catch (Throwable t) { throw new RuntimeException(t); } } } public Object getArg(int index) { if (index >= args.length) throw new ArrayIndexOutOfBoundsException(); return args[index]; } public void setArg(int index, Object value) { if (index >= args.length) throw new ArrayIndexOutOfBoundsException(); args[index] = value; } public Object[] getArgs() { return args; } /** * Get the target object which be intercepted * <pre> * Example: * OrderService os = getTarget(); * </pre> */ public <T> T getTarget() { return (T)target; } /** * Return the method of this action. * <p> * You can getMethod.getAnnotations() to get annotation on action method to do more things */ public Method getMethod() { if (action != null) return action.getMethod(); return method; } /** * Return the method name of this action's method. */ public String getMethodName() { if (action != null) return action.getMethodName(); return method.getName(); } /** * Get the return value of the target method */ public <T> T getReturnValue() { return (T)returnValue; } /** * Set the return value of the target method */ public void setReturnValue(Object returnValue) { this.returnValue = returnValue; } // --------- /** * Return the controller of this action. */ public Controller getController() { if (action == null) throw new RuntimeException("This method can only be used for action interception"); return (Controller)target; } /** * Return the action key. * actionKey = controllerKey + methodName */ public String getActionKey() { if (action == null) throw new RuntimeException("This method can only be used for action interception"); return action.getActionKey(); } /** * Return the controller key. */ public String getControllerKey() { if (action == null) throw new RuntimeException("This method can only be used for action interception"); return action.getControllerKey(); } /** * Return view path of this controller. */ public String getViewPath() { if (action == null) throw new RuntimeException("This method can only be used for action interception"); return action.getViewPath(); } /** * return true if it is action invocation. */ public boolean isActionInvocation() { return action != null; } }