001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.web.handler;
017
018import com.jfinal.aop.Interceptor;
019import com.jfinal.aop.Invocation;
020import com.jfinal.core.Action;
021import com.jfinal.core.Controller;
022import io.jboot.aop.InterceptorBuilderManager;
023import io.jboot.aop.InterceptorCache;
024
025import java.lang.reflect.InvocationTargetException;
026import java.lang.reflect.Method;
027
028/**
029 * @author michael yang (fuhai999@gmail.com)
030 */
031public class JbootActionInvocation extends Invocation {
032
033    protected Action action;
034    protected Object target;
035    protected Object[] args;
036
037    protected Interceptor[] inters;
038    protected int index = 0;
039
040    protected Object returnValue;
041
042
043    protected static InterceptorBuilderManager builderManager = InterceptorBuilderManager.me();
044
045    public JbootActionInvocation(Action action, Controller controller) {
046
047        this.action = action;
048        this.inters = buildInterceptors(action);
049        this.target = controller;
050
051        this.args = action.getParameterGetter().get(action, controller);
052    }
053
054
055    protected Interceptor[] buildInterceptors(Action action) {
056
057        InterceptorCache.MethodKey key = InterceptorCache.getMethodKey(action.getControllerClass(), action.getMethod());
058        Interceptor[] inters = InterceptorCache.get(key);
059        if (inters == null) {
060            inters = action.getInterceptors();
061            inters = builderManager.build(action.getControllerClass(), action.getMethod(), inters);
062            InterceptorCache.put(key, inters);
063        }
064
065        return inters;
066    }
067
068
069    @Override
070    public void invoke() {
071        if (index < inters.length) {
072            inters[index++].intercept(this);
073        } else if (index++ == inters.length) {    // index++ ensure invoke action only one time
074            try {
075                // Invoke the action
076                returnValue = action.getMethod().invoke(target, args);
077            } catch (InvocationTargetException e) {
078                Throwable t = e.getTargetException();
079                if (t == null) {
080                    t = e;
081                }
082                throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(t);
083            } catch (RuntimeException e) {
084                throw e;
085            } catch (Throwable t) {
086                throw new RuntimeException(t);
087            }
088        }
089    }
090
091
092    @Override
093    public Object getArg(int index) {
094        if (index >= args.length) {
095            throw new ArrayIndexOutOfBoundsException();
096        }
097        return args[index];
098    }
099
100
101    @Override
102    public void setArg(int index, Object value) {
103        if (index >= args.length) {
104            throw new ArrayIndexOutOfBoundsException();
105        }
106        args[index] = value;
107    }
108
109
110    @Override
111    public Object[] getArgs() {
112        return args;
113    }
114
115
116    @Override
117    public <T> T getTarget() {
118        return (T) target;
119    }
120
121    /**
122     * Return the method of this action.
123     * <p>
124     * You can getMethod.getAnnotations() to get annotation on action method to do more things
125     */
126    @Override
127    public Method getMethod() {
128        return action.getMethod();
129    }
130
131    /**
132     * Return the method name of this action's method.
133     */
134    @Override
135    public String getMethodName() {
136        return action.getMethodName();
137    }
138
139    /**
140     * Get the return value of the target method
141     */
142    @Override
143    public <T> T getReturnValue() {
144        return (T) returnValue;
145    }
146
147
148    @Override
149    public void setReturnValue(Object returnValue) {
150        this.returnValue = returnValue;
151    }
152    // ---------
153
154    /**
155     * Return the controller of this action.
156     */
157    @Override
158    public Controller getController() {
159        return (Controller) target;
160    }
161
162    /**
163     * Return the action key.
164     * actionKey = controllerPath + methodName
165     */
166    @Override
167    public String getActionKey() {
168        return action.getActionKey();
169    }
170
171    /**
172     * Return the controller path.
173     */
174    @Override
175    public String getControllerPath() {
176        return action.getControllerPath();
177    }
178
179    /**
180     * 该方法已改名为 getControllerPath()
181     */
182    @Override
183    @Deprecated
184    public String getControllerKey() {
185        return getControllerPath();
186    }
187
188    /**
189     * Return view path of this controller.
190     */
191    @Override
192    public String getViewPath() {
193        return action.getViewPath();
194    }
195
196    /**
197     * return true if it is action invocation.
198     */
199    @Override
200    public boolean isActionInvocation() {
201        return action != null;
202    }
203}