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.components.limiter;
017
018import com.jfinal.aop.Invocation;
019import com.jfinal.core.Controller;
020import io.jboot.Jboot;
021import io.jboot.exception.JbootException;
022import io.jboot.utils.ClassUtil;
023import io.jboot.utils.RequestUtil;
024import io.jboot.utils.StrUtil;
025
026import java.lang.reflect.Method;
027
028/**
029 * 默认的限流处理器
030 */
031public class LimitFallbackProcesserDefault implements LimitFallbackProcesser {
032
033    protected LimitConfig config = Jboot.config(LimitConfig.class);
034
035    @Override
036    public void process(String resource, String fallback, Invocation inv) {
037
038        if (StrUtil.isNotBlank(fallback)) {
039            doProcessFallback(fallback, inv);
040            return;
041        }
042
043        if (inv.isActionInvocation()) {
044            doProcessWebLimit(resource, inv);
045        } else {
046            doProcessServiceLimit(resource, inv);
047        }
048    }
049
050    protected void doProcessFallback(String fallback, Invocation inv) {
051        Method method = getMethodByName(fallback, inv);
052        if (method == null) {
053            throw new JbootException("can not find method[" + fallback + "] in class " +
054                    ClassUtil.getUsefulClass(inv.getTarget().getClass()));
055        }
056
057        try {
058            method.setAccessible(true);
059            Object invokeValue = method.getParameterCount() == 0
060                    ? method.invoke(inv.getTarget())
061                    : method.invoke(inv.getTarget(), inv.getArgs());
062            inv.setReturnValue(invokeValue);
063        } catch (Exception e) {
064            e.printStackTrace();
065        }
066    }
067
068
069    protected Method getMethodByName(String methodName, Invocation inv) {
070        Class clazz = ClassUtil.getUsefulClass(inv.getTarget().getClass());
071        Method[] methods = clazz.getMethods();
072        for (Method m : methods) {
073            if (methodName.equals(m.getName())) {
074                return m;
075            }
076        }
077        return null;
078    }
079
080
081    /**
082     * 处理 Controller 的限流
083     *
084     * @param resource
085     * @param inv
086     */
087    protected void doProcessWebLimit(String resource, Invocation inv) {
088
089        Controller controller = inv.getController();
090        controller.getResponse().setStatus(config.getDefaultHttpCode());
091
092        if (RequestUtil.isAjaxRequest(controller.getRequest())) {
093            controller.renderJson(config.getDefaultAjaxContent());
094        }
095        //非ajax的正常请求
096        else {
097            String limitView = config.getDefaultHtmlView();
098            if (limitView != null) {
099                controller.render(limitView);
100            } else {
101                controller.renderText("reqeust limit.");
102            }
103        }
104    }
105
106    /**
107     * 处理 Service 层的限流
108     *
109     * @param resource
110     * @param inv
111     */
112    protected void doProcessServiceLimit(String resource, Invocation inv) {
113        if (Jboot.isDevMode()) {
114            System.err.println(resource + " is limited by LimitFallbackProcesser, return null");
115        }
116    }
117}