<commit_before>package org.voovan.http.server.module.annontationRouter.router;

import org.voovan.http.server.*;
import org.voovan.http.server.module.annontationRouter.AnnotationModule;
import org.voovan.http.server.module.annontationRouter.annotation.*;
import org.voovan.http.server.exception.AnnotationRouterException;
import org.voovan.tools.TEnv;
import org.voovan.tools.TFile;
import org.voovan.tools.TString;
import org.voovan.tools.json.JSON;
import org.voovan.tools.log.Logger;
import org.voovan.tools.reflect.TReflect;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 通过注解实现的路由
 *
 * @author: helyho
 * Voovan Framework.
 * WebSite: https://github.com/helyho/Voovan
 * Licence: Apache v2 License
 */
public class AnnotationRouter implements HttpRouter {

    private static Map<Class, Object> singletonObjs = new ConcurrentHashMap<Class, Object>();

    private Class clazz;
    private Method method;
    private Router classRouter;

    /**
     * 构造函数
     * @param clazz   Class对象
     * @param method  方法对象
     */
    public AnnotationRouter(Class clazz, Method method, Router classRouter) {
        this.clazz = clazz;
        this.method = method;
        this.classRouter = classRouter;

        //如果是单例,则进行预实例化
        if(classRouter.singleton() && !singletonObjs.containsKey(clazz)){
            try {
                singletonObjs.put(clazz, clazz.newInstance());
            } catch (Exception e) {
                Logger.error("New a singleton object error", e);
            }
        }
    }

    /**
     * 扫描包含Router注解的类
     *
     * @param httpModule   AnnotationModule对象用于注册路由
     * @throws IOException                  IO 异常
     * @throws ReflectiveOperationException 反射异常
     */
    public static void scanRouterClassAndRegister(AnnotationModule httpModule) {
        int routeMethodNum = 0;
        WebServer webServer = httpModule.getWebServer();
        try {
            //查找
            List<Class> routerClasses = TEnv.searchClassInEnv(httpModule.getScanRouterPackage(), new Class[]{Router.class});
            for (Class routerClass : routerClasses) {
                Method[] methods = routerClass.getMethods();
                Router annonClassRouter = (Router) routerClass.getAnnotation(Router.class);
                String classRouterPath = annonClassRouter.path().isEmpty() ? annonClassRouter.value() : annonClassRouter.path();
                String classRouterMethod = annonClassRouter.method();

                //使用类名指定默认路径
                if (classRouterPath.isEmpty()) {
                    classRouterPath = "/" + routerClass.getSimpleName();
                }

                for (Method method : methods) {
                    if (method.isAnnotationPresent(Router.class)) {
                        Router annonMethodRouter = method.getAnnotation(Router.class);
                        String methodRouterPath = annonMethodRouter.path().isEmpty() ? annonMethodRouter.value() : annonMethodRouter.path();;
                        String methodRouterMethod = annonMethodRouter.method();

                        //使用方法名指定默认路径
                        if (methodRouterPath.isEmpty()) {
                            methodRouterPath = "/" + method.getName();
                        }

                        //拼装路径
                        String routePath = classRouterPath + methodRouterPath;

                        //如果方法上的注解指定了 Method 则使用方法上的注解指定的,否则使用类上的注解指定的
                        String routeMethod = methodRouterMethod != null ? methodRouterMethod : classRouterMethod;

                        //为方法的参数准备带参数的路径
                        String paramPath = "";
                        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
                        Class[] parameterTypes = method.getParameterTypes();
                        for (int i=0; i < parameterAnnotations.length; i++) {
                            Annotation[] annotations = parameterAnnotations[i];

                            if(annotations.length==0 &&
                                    parameterTypes[i] != HttpRequest.class &&
                                    parameterTypes[i] != HttpResponse.class &&
                                    parameterTypes[i] != HttpSession.class ){
                                paramPath = paramPath + "/:param"+(i+1);
                                continue;
                            }

                            for (Annotation annotation : annotations) {
                                if (annotation instanceof Param) {
                                    paramPath = paramPath + "/:" + ((Param) annotation).value();
                                }
                            }
                        }

                        //判断路由是否注册过
                        if (webServer.getHttpRouters().get(routeMethod) == null ||
                                !webServer.getHttpRouters().get(routeMethod).containsKey(routePath)) {

                            //构造注解路由器
                            AnnotationRouter annotationRouter = new AnnotationRouter(routerClass, method, annonClassRouter);

                            //注册路由,不带路径参数的路由
                            httpModule.otherMethod(routeMethod, routePath, annotationRouter);
                            Logger.simple("[Router] add annotation route: " + routeMethod + " - " + routePath);
                            routeMethodNum++;

                            if(!paramPath.isEmpty()) {
                                routePath = routePath + paramPath;

                                //注册路由,带路径参数的路由
                                httpModule.otherMethod(routeMethod, routePath, annotationRouter);
                                Logger.simple("[Router] add annotation route: " + routeMethod + " - " + routePath);
                                routeMethodNum++;
                            }
                        }
                    }
                }
            }

            if(routeMethodNum>0) {
                Logger.simple(TFile.getLineSeparator() + "[SYSTEM] Scan some class annotation by Router: " + routerClasses.size() +
                        ". Unregister Router method annotation by route: " + routeMethodNum + ".");
            }
        } catch (Exception e){
            Logger.error("Scan router class error.", e);
        }
    }

    /**
     * 将一个 Http 请求映射到一个类的方法调用
     * @param request   http 请求对象
     * @param response  http 响应对象
     * @param clazz     Class 对象
     * @param method    Method 对象
     * @return  返回值
     * @throws Exception 调用过程中的异常
     */<commit_msg>fix: 修复 TredMap.containsKey 的 bug<commit_after>package org.voovan.http.server.module.annontationRouter.router;

import org.voovan.http.server.*;
import org.voovan.http.server.module.annontationRouter.AnnotationModule;
import org.voovan.http.server.module.annontationRouter.annotation.*;
import org.voovan.http.server.exception.AnnotationRouterException;
import org.voovan.tools.TEnv;
import org.voovan.tools.TFile;
import org.voovan.tools.TString;
import org.voovan.tools.json.JSON;
import org.voovan.tools.log.Logger;
import org.voovan.tools.reflect.TReflect;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 通过注解实现的路由
 *
 * @author: helyho
 * Voovan Framework.
 * WebSite: https://github.com/helyho/Voovan
 * Licence: Apache v2 License
 */
public class AnnotationRouter implements HttpRouter {

    private static Map<Class, Object> singletonObjs = new ConcurrentHashMap<Class, Object>();

    private Class clazz;
    private Method method;
    private Router classRouter;

    /**
     * 构造函数
     * @param clazz   Class对象
     * @param method  方法对象
     */
    public AnnotationRouter(Class clazz, Method method, Router classRouter) {
        this.clazz = clazz;
        this.method = method;
        this.classRouter = classRouter;

        //如果是单例,则进行预实例化
        if(classRouter.singleton() && !singletonObjs.containsKey(clazz)){
            try {
                singletonObjs.put(clazz, clazz.newInstance());
            } catch (Exception e) {
                Logger.error("New a singleton object error", e);
            }
        }
    }

    /**
     * 扫描包含Router注解的类
     *
     * @param httpModule   AnnotationModule对象用于注册路由
     * @throws IOException                  IO 异常
     * @throws ReflectiveOperationException 反射异常
     */
    public static void scanRouterClassAndRegister(AnnotationModule httpModule) {
        int routeMethodNum = 0;
        WebServer webServer = httpModule.getWebServer();
        try {
            //查找
            List<Class> routerClasses = TEnv.searchClassInEnv(httpModule.getScanRouterPackage(), new Class[]{Router.class});
            for (Class routerClass : routerClasses) {
                Method[] methods = routerClass.getMethods();
                Router annonClassRouter = (Router) routerClass.getAnnotation(Router.class);
                String classRouterPath = annonClassRouter.path().isEmpty() ? annonClassRouter.value() : annonClassRouter.path();
                String classRouterMethod = annonClassRouter.method();

                //使用类名指定默认路径
                if (classRouterPath.isEmpty()) {
                    classRouterPath = "/" + routerClass.getSimpleName();
                }

                for (Method method : methods) {
                    if (method.isAnnotationPresent(Router.class)) {
                        Router annonMethodRouter = method.getAnnotation(Router.class);
                        String methodRouterPath = annonMethodRouter.path().isEmpty() ? annonMethodRouter.value() : annonMethodRouter.path();;
                        String methodRouterMethod = annonMethodRouter.method();

                        //使用方法名指定默认路径
                        if (methodRouterPath.isEmpty()) {
                            methodRouterPath = "/" + method.getName();
                        }

                        //拼装路径
                        String routePath = classRouterPath + methodRouterPath;

                        //如果方法上的注解指定了 Method 则使用方法上的注解指定的,否则使用类上的注解指定的
                        String routeMethod = methodRouterMethod != null ? methodRouterMethod : classRouterMethod;

                        //为方法的参数准备带参数的路径
                        String paramPath = "";
                        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
                        Class[] parameterTypes = method.getParameterTypes();
                        for (int i=0; i < parameterAnnotations.length; i++) {
                            Annotation[] annotations = parameterAnnotations[i];

                            if(annotations.length==0 &&
                                    parameterTypes[i] != HttpRequest.class &&
                                    parameterTypes[i] != HttpResponse.class &&
                                    parameterTypes[i] != HttpSession.class ){
                                paramPath = paramPath + "/:param"+(i+1);
                                continue;
                            }

                            for (Annotation annotation : annotations) {
                                if (annotation instanceof Param) {
                                    paramPath = paramPath + "/:" + ((Param) annotation).value();
                                }
                            }
                        }

                        //这里这么做是为了处理 TreeMap 的 containsKey 方法的 bug


                        //判断路由是否注册过
                        if (webServer.getHttpRouters().get(routeMethod) == null) {

                            //这里这么做是为了处理 TreeMap 的 containsKey 方法的 bug
                            Map routerMaps = new HashMap();
                            routerMaps.putAll(webServer.getHttpRouters().get(routeMethod));

                            if(!routerMaps.containsKey(routePath)) {
                                //构造注解路由器
                                AnnotationRouter annotationRouter = new AnnotationRouter(routerClass, method, annonClassRouter);

                                //注册路由,不带路径参数的路由
                                httpModule.otherMethod(routeMethod, routePath, annotationRouter);
                                Logger.simple("[Router] add annotation route: " + routeMethod + " - " + routePath);
                                routeMethodNum++;

                                if (!paramPath.isEmpty()) {
                                    routePath = routePath + paramPath;

                                    //注册路由,带路径参数的路由
                                    httpModule.otherMethod(routeMethod, routePath, annotationRouter);
                                    Logger.simple("[Router] add annotation route: " + routeMethod + " - " + routePath);
                                    routeMethodNum++;
                                }
                            }
                        }
                    }
                }
            }

            if(routeMethodNum>0) {
                Logger.simple(TFile.getLineSeparator() + "[SYSTEM] Scan some class annotation by Router: " + routerClasses.size() +
                        ". Unregister Router method annotation by route: " + routeMethodNum + ".");
            }
        } catch (Exception e){
            Logger.error("Scan router class error.", e);
        }
    }

    /**
     * 将一个 Http 请求映射到一个类的方法调用
     * @param request   http 请求对象
     * @param response  http 响应对象
     * @param clazz     Class 对象
     * @param method    Method 对象
     * @return  返回值
     * @throws Exception 调用过程中的异常
     */
{'fraction_non_alphanumeric': 0.0914405311778291, 'fraction_numerical': 0.0008660508083140878, 'mean_word_length': 1.5360541727672035, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3408106', 'n_tokens_mistral': 3677, 'n_tokens_neox': 3574, 'n_words': 662}