Package com.bj58.argo.internal

Source Code of com.bj58.argo.internal.ActionInfo

package com.bj58.argo.internal;

import com.bj58.argo.Argo;
import com.bj58.argo.ArgoException;
import com.bj58.argo.ActionResult;
import com.bj58.argo.annotations.GET;
import com.bj58.argo.annotations.POST;
import com.bj58.argo.annotations.Path;
import com.bj58.argo.ArgoController;
import com.bj58.argo.interceptor.PostInterceptor;
import com.bj58.argo.interceptor.PreInterceptor;
import com.bj58.argo.interceptor.PostInterceptorAnnotation;
import com.bj58.argo.interceptor.PreInterceptorAnnotation;
import com.bj58.argo.route.RouteBag;
import com.bj58.argo.thirdparty.AnnotationUtils;
import com.bj58.argo.thirdparty.AntPathMatcher;
import com.bj58.argo.thirdparty.PathMatcher;
import com.bj58.argo.utils.ClassUtils;
import com.bj58.argo.utils.Pair;
import com.bj58.argo.utils.converter.ConverterFactory;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ActionInfo {

    private final ControllerInfo controllerInfo;
    private final Method method;
    private final Argo argo;

    /**
     * path匹配模式,联合了Controller上path,并去除后置"/",
     */
    private final String pathPattern;

    /**
     * Http Method GET
     */
    private final boolean isGet;

    /**
     * http method POST
     */
    private final boolean isPost;

    /**
     * 方法上所有参数名,按顺序排列
     */
    private final List<String> paramNames;

    /**
     * 方法上所有参数类型,按顺序排列
     */
    private final List<Class<?>> paramTypes;

    /**
     * 所有annotation,包括并覆盖controller上的annotation,
     */
    private final Set<Annotation> annotations;

    /**
     * 所有前置拦截器,按拦截器的order升序排列
     */
    private final List<PreInterceptor> preInterceptors;

    /**
     * 所有后置拦截器,按拦截器的order降序排列
     */
    private final List<PostInterceptor> postInterceptors;

    /**
     * 匹配的优先级
     */
    private final int order;

    /**
     * 是否是模版匹配
     */
    private final boolean isPattern;

    /**
     * 利用Ant匹配模型处理url
     */
    private final PathMatcher pathMatcher = new AntPathMatcher();

    private final ConverterFactory converter = new ConverterFactory();

    public ActionInfo(ControllerInfo controllerInfo, Method method, Argo argo) {
        this.controllerInfo = controllerInfo;
        this.method = method;
        this.argo = argo;

        Path path = AnnotationUtils.findAnnotation(method, Path.class);
        this.order = path.order();

        this.pathPattern = simplyPathPattern(controllerInfo, path);

        this.paramTypes = ImmutableList.copyOf(method.getParameterTypes());
        this.paramNames = ImmutableList.copyOf(ClassUtils.getMethodParamNames(controllerInfo.getClazz(), method));

        // 计算匹配的优先级,精确匹配还是模版匹配
        isPattern = pathMatcher.isPattern(pathPattern)
                || paramTypes.size() > 0;

        Pair<Boolean, Boolean> httpMethodPair = pickupHttpMethod(controllerInfo, method);
        this.isGet = httpMethodPair.getKey();
        this.isPost = httpMethodPair.getValue();

        annotations = collectAnnotations(controllerInfo, method);

        // 拦截器
        List<InterceptorInfo> interceptorInfoList = findInterceptors();
        preInterceptors = getPreInterceptorList(interceptorInfoList);
        postInterceptors = getPostInterceptorList(interceptorInfoList);
    }

    public String getPathPattern() {
        return pathPattern;
    }


    ArgoController controller() {
        return controllerInfo.getController();
    }

    Method method() {
        return method;
    }

    public boolean isGet() {
        return isGet;
    }

    public boolean isPost() {
        return isPost;
    }

    public List<Class<?>> getParamTypes() {
        return paramTypes;
    }

    public List<String> getParamNames() {
        return paramNames;
    }

    public Set<Annotation> annotations() {
        return annotations;
    }

    public boolean isPattern() {
        return isPattern;
    }

    public int getOrder() {
        return order;
    }

    public List<PreInterceptor> getPreInterceptors() {
        return preInterceptors;
    }

    public List<PostInterceptor> getPostInterceptors() {
        return postInterceptors;
    }

    PathMatcher getPathMatcher() {
        return pathMatcher;
    }

    Argo getArgo() {
        return argo;
    }

    ConverterFactory getConverter() {
        return converter;
    }

    boolean match(RouteBag bag, Map<String, String> uriTemplateVariables) {
        return getPathMatcher().doMatch(getPathPattern(), bag.getSimplyPath(), true, uriTemplateVariables);
    }

    boolean matchHttpMethod(RouteBag bag) {

        return (bag.isGet() && isGet())
                || (bag.isPost() && isPost());
    }

    ActionResult invoke(Map<String, String> urlParams) {
        Object[] param = new Object[getParamTypes().size()];
        for(int index = 0; index < getParamNames().size(); index++){
            String paramName = getParamNames().get(index);
            Class<?> clazz = getParamTypes().get(index);

            String v = urlParams.get(paramName);

            if (v == null)
                throw ArgoException.newBuilder("Invoke exception:")
                        .addContextVariable(paramName, "null")
                        .build();

            // fixMe: move to init
            if(!getConverter().canConvert(clazz))
                throw ArgoException.newBuilder("Invoke cannot convert parameter.")
                        .addContextVariable(paramName, "expect " + clazz.getName() + " but value is " + v)
                        .build();

            param[index] = getConverter().convert(clazz, v);
        }

        try {
            Object result = method().invoke(controller(), param);
            return ActionResult.class.cast(result);
        } catch (Exception e) {
            throw ArgoException.newBuilder("invoke exception.", e)
                    .addContextVariables(urlParams)
                    .build();
        }
    }


    String simplyPathPattern(ControllerInfo controllerInfo, Path path) {
        String originPathPattern = combinePathPattern(controllerInfo, path);
        return simplyPathPattern(originPathPattern);
    }

    /**
     *收集方法上所有Annotation,包括Controller上标志
     * @param controllerInfo controller信息
     * @param method 方法
     * @return 方法上所有Annotation,包括Controller
     */
    ImmutableSet<Annotation> collectAnnotations(ControllerInfo controllerInfo, Method method) {
        return ImmutableSet.<Annotation>builder()
                .add(method.getAnnotations())
                .addAll(controllerInfo.getAnnotations())
                .build();

    }

    Pair<Boolean, Boolean> pickupHttpMethod(ControllerInfo controllerInfo, Method method) {
        boolean isGet = AnnotationUtils.findAnnotation(method, GET.class) != null;
        boolean isPost = AnnotationUtils.findAnnotation(method, POST.class) != null;

        if (!isGet && !isPost) {
            isGet = controllerInfo.isGet();
            isPost = controllerInfo.isPost();
        }

        return Pair.build(isGet, isPost);

    }

    private String simplyPathPattern(String combinedPattern) {
        if (combinedPattern.length() > 1 && combinedPattern.endsWith("/"))
            combinedPattern = combinedPattern.substring(0, combinedPattern.length() - 2);
        return combinedPattern;
    }

    private String combinePathPattern(ControllerInfo controllerInfo, Path path) {
        String pathPattern = path.value();

        String controllerPattern = controllerInfo.getPathUrl();
        return getPathMatcher().combine(controllerPattern, pathPattern);
    }



    List<PreInterceptor> getPreInterceptorList( List<InterceptorInfo> interceptorInfoList) {

        ImmutableList.Builder<PreInterceptor> builder = ImmutableList.builder();

        for(InterceptorInfo interceptorInfo : interceptorInfoList) {
            PreInterceptor preInterceptor = interceptorInfo.getPreInterceptor();
            if (preInterceptor != null)
                builder.add(preInterceptor);
        }

        return builder.build();
    }

    List<PostInterceptor> getPostInterceptorList( List<InterceptorInfo> interceptorInfoList) {

        ImmutableList.Builder<PostInterceptor> builder = ImmutableList.builder();

        for(InterceptorInfo interceptorInfo : interceptorInfoList) {
            PostInterceptor postInterceptor = interceptorInfo.getPostInterceptor();
            if (postInterceptor != null)
                builder.add(postInterceptor);
        }

        //反转,对于post先执行排序高的,再执行排序低的
        return builder.build().reverse();
    }

    List<InterceptorInfo> findInterceptors() {

        List<InterceptorInfo> interceptorInfoList = Lists.newArrayList();

        for(Annotation ann : this.annotations()) {

            InterceptorInfo interceptorInfo = findInterceptorInfo(ann);
            if (interceptorInfo == null)
                continue;

            interceptorInfoList = merge(interceptorInfoList, interceptorInfo);
        }

        return interceptorInfoList;
    }

    private InterceptorInfo findInterceptorInfo(Annotation ann) {
        PreInterceptorAnnotation preA = AnnotationUtils.findAnnotation(ann.getClass(), PreInterceptorAnnotation.class);
        PostInterceptorAnnotation postA = AnnotationUtils.findAnnotation(ann.getClass(), PostInterceptorAnnotation.class);
        if (preA == null && postA == null)
            return null;

        Object orderObject = AnnotationUtils.getValue(ann, "order");

        int order = orderObject == null ? 100
                : (Integer)orderObject;   // xxx: maybe throw exception.

        PreInterceptor preInterceptor = (preA == null ? null : getArgo().getInstance(preA.value()));
        PostInterceptor postInterceptor = (postA == null ? null : getArgo().getInstance(postA.value()));

        return new InterceptorInfo(ann, order, preInterceptor, postInterceptor);
    }

    private List<InterceptorInfo> merge(List<InterceptorInfo> interceptorInfoList, InterceptorInfo interceptorInfo) {

        int position = interceptorInfoList.size();

        for (int index = 0; index < interceptorInfoList.size(); index++) {
            InterceptorInfo item = interceptorInfoList.get(index);
            // 如果annotation已存在,则忽略(先处理方法的Annotation,再处理类的Annotation)
            if (item.sample(interceptorInfo))
                return interceptorInfoList;

            if(item.getOrder() > interceptorInfo.getOrder()) {
                position = index;
            }
        }

        interceptorInfoList.add(position, interceptorInfo);
        return interceptorInfoList;
    }

    private class InterceptorInfo {
        private final Annotation annotation;
        private final PreInterceptor preInterceptor;
        private final PostInterceptor postInterceptor;
        private final int order;

        private InterceptorInfo(Annotation annotation, int order, PreInterceptor preInterceptor, PostInterceptor postInterceptor) {
            this.annotation = annotation;
            this.order = order;
            this.preInterceptor = preInterceptor;
            this.postInterceptor = postInterceptor;
        }

        private Annotation getAnnotation() {
            return annotation;
        }

        public PreInterceptor getPreInterceptor() {
            return preInterceptor;
        }

        public PostInterceptor getPostInterceptor() {
            return postInterceptor;
        }

        public int getOrder() {
            return order;
        }

        public boolean sample(InterceptorInfo other) {
            return this.getAnnotation().annotationType() == other.getAnnotation().annotationType();
        }
    }


}
TOP

Related Classes of com.bj58.argo.internal.ActionInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.