All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cybermkd.route.core.Route Maven / Gradle / Ivy

package com.cybermkd.route.core;


import com.cybermkd.common.Constant;
import com.cybermkd.common.entity.Entity;
import com.cybermkd.common.http.*;
import com.cybermkd.common.http.exception.WebException;
import com.cybermkd.common.http.result.HttpStatus;
import com.cybermkd.common.util.Joiner;
import com.cybermkd.common.util.analysis.ParamAttribute;
import com.cybermkd.common.util.analysis.ParamNamesScaner;
import com.cybermkd.common.util.json.Jsoner;
import com.cybermkd.common.util.json.ModelDeserializer;
import com.cybermkd.common.util.stream.StreamReader;
import com.cybermkd.log.Logger;
import com.cybermkd.route.core.multipart.MultipartBuilder;
import com.cybermkd.route.core.multipart.MultipartParam;
import com.cybermkd.route.exception.InitException;
import com.cybermkd.route.interceptor.Interceptor;
import com.cybermkd.route.render.RenderFactory;
import com.cybermkd.route.valid.Validator;
import com.alibaba.fastjson.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.cybermkd.common.util.Checker.checkArgument;
import static com.cybermkd.common.util.Checker.checkNotNull;

/**
 * Created by ice on 14-12-19.
 */
public class Route {

    public static final String PARAM_PATTERN = "([^\\/]+)";
    private static final Logger logger = Logger.getLogger(Route.class);
    private static final PathParserCharProcessor regularCharPathParserCharProcessor = new PathParserCharProcessor() {

        public void handle(int curChar, PathPatternParser pathPatternParser) {
            if (curChar == '{') {
                pathPatternParser.processor = new CurlyBracesPathParamPathParserCharProcessor();
            } else if (curChar == ':') {
                pathPatternParser.processor = new SimpleColumnBasedPathParamParserCharProcessor();
            } else {
                pathPatternParser.patternBuilder.appendCodePoint(curChar);
                pathPatternParser.stdPathPatternBuilder.appendCodePoint(curChar);
            }
        }

        public void end(PathPatternParser pathPatternParser) {
        }
    };
    private final String httpMethod;
    private final String pathPattern;
    private final String stdPathPattern;
    private final Pattern pattern;
    private final List pathParamNames;
    private final Class resourceClass;
    private final Method method;
    private final List allParamNames;
    private final int[] allLineNumbers;
    private final List> allParamTypes;
    private final List allGenericParamTypes;
    private final Interceptor[] interceptors;
    private final int[][] interceptorsLineNumbers;
    private final Validator[] validators;
    private final int[][] validsLineNumbers;
    private final MultipartBuilder multipartBuilder;
    private final Map headers;

    public Route(Class resourceClass, ParamAttribute paramAttribute, String httpMethod, String pathPattern, Method method, Interceptor[] interceptors, String des, Validator[] validators, MultipartBuilder multipartBuilder, Map headers) {
        this.resourceClass = resourceClass;
        this.httpMethod = checkNotNull(httpMethod);
        this.pathPattern = checkNotNull(pathPattern);
        this.method = method;
        this.multipartBuilder = multipartBuilder;
        this.interceptors = interceptors;

        this.allParamNames = paramAttribute.getNames();
        this.allLineNumbers = paramAttribute.getLines();
        this.allParamTypes = Arrays.asList(method.getParameterTypes());
        this.allGenericParamTypes = Arrays.asList(method.getGenericParameterTypes());
        this.validators = validators;
        this.headers = headers;
        //获取拦截器的行号
        if (Constant.showRoute) {
            this.interceptorsLineNumbers = new int[interceptors.length][];
            //获取参数
            ParamAttribute paramAttr;
            int i = 0;
            for (Interceptor interceptor : interceptors) {
                try {
                    paramAttr = ParamNamesScaner.getParamNames(interceptor.getClass().getMethod("intercept", RouteInvocation.class));
                } catch (NoSuchMethodException e) {
                    throw new InitException(e.getMessage(), e);
                }
                this.interceptorsLineNumbers[i] = paramAttr.getLines();
                i++;
            }
            //验证器
            this.validsLineNumbers = new int[validators.length][];
            i = 0;
            for (Validator validator : validators) {
                try {
                    paramAttr = ParamNamesScaner.getParamNames(validator.getClass().getMethod("validate", Params.class, RouteMatch.class));
                } catch (NoSuchMethodException e) {
                    throw new InitException(e.getMessage(), e);
                }
                this.validsLineNumbers[i] = paramAttr.getLines();
                i++;
            }
        } else {
            this.validsLineNumbers = null;
            this.interceptorsLineNumbers = null;
        }
        PathPatternParser s = new PathPatternParser(pathPattern);
        s.parse();

        this.pattern = Pattern.compile(s.patternBuilder.toString());
        this.stdPathPattern = s.stdPathPatternBuilder.toString();
        this.pathParamNames = s.pathParamNames;
        //check arguments
        for (String pName : pathParamNames) {
            if (!allParamNames.contains(pName)) {
                throw new IllegalArgumentException("PathParameter '" + pName + "' could not found in method arguments at " + resourceClass.getName() + "(" + resourceClass.getSimpleName() + ".java:" + allLineNumbers[0] + ")");
            }
        }

        if (logger.isInfoEnabled()) {
            //print route
            StringBuilder sb = new StringBuilder("\n\nBuild route ----------------- ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append(" ------------------------------");
            sb.append("\nResource     : ").append(resourceClass.getName()).append("(").append(resourceClass.getSimpleName()).append(".java:").append(allLineNumbers[0]).append(")");
            sb.append("\nMethod       : ").append(method.getName());
            sb.append("\nPathPattern  : ").append(httpMethod).append(" ").append(pathPattern);
            //print params
            StringBuilder sbPath = new StringBuilder("\nPathParams   : ");
            StringBuilder sbOther = new StringBuilder("\nOtherParams  : ");
            int pSize = allParamNames.size();
            String pName;
            if (pSize > 0) {

                for (int i = 0; i < pSize; i++) {
                    pName = allParamNames.get(i);
                    if (pathParamNames.contains(pName)) {
                        sbPath.append(pName).append("(").append(allGenericParamTypes.get(i)).append(")  ");
                    } else {
                        sbOther.append(pName).append("(").append(allGenericParamTypes.get(i)).append(")  ");
                    }
                }
            }

            sb.append(sbPath).append(sbOther);

            Type returnType = method.getGenericReturnType();
            sb.append("\nReturnType   : ").append(returnType);
            sb.append("\nDescriptions : ").append(des);

            if (validators != null && validators.length > 0 && validsLineNumbers != null) {
                sb.append("\nValidators   : ");
                int i = 0;
                for (Validator validator : validators) {
                    if (i > 0)
                        sb.append("\n               ");
                    Class vc = validator.getClass();
                    sb.append(vc.getName()).append("(").append(vc.getSimpleName()).append(".java:").append(validsLineNumbers[i][0]).append(")");
                    i++;
                }
            }

            if (interceptors != null && interceptors.length > 0 && interceptorsLineNumbers != null) {
                sb.append("\nInterceptors : ");
                int i = 0;
                for (Interceptor interceptor : interceptors) {
                    if (i > 0) {
                        sb.append("\n               ");
                    }
                    Class ic = interceptor.getClass();
                    sb.append(ic.getName()).append("(").append(ic.getSimpleName()).append(".java:").append(interceptorsLineNumbers[i][0]).append(")");
                    i++;
                }
            }

            sb.append("\n--------------------------------------------------------------------------------\n");
            logger.info(sb.toString());
        }
    }

    /**
     * 匹配路由
     *
     * @param request  request对象
     * @param response response对象
     * @return route
     */
    public RouteMatch match(HttpRequest request, HttpResponse response) {
        if (!this.httpMethod.equals(request.getHttpMethod())) {
            return null;
        }
        String restPath = request.getRestPath();

        String extension = "";
        if (restPath.contains(".")) {
            int index = restPath.lastIndexOf(".");
            extension = restPath.substring(index + 1);
            if (RenderFactory.contains(extension)) {
                restPath = restPath.substring(0, index);
            } else {
                extension = "";
            }
        }

        Matcher m = pattern.matcher(restPath);
        if (!m.matches()) {
            return null;
        }
        if (headers.size() > 0) {
            for (Map.Entry headersEntry : headers.entrySet()) {
                if (!headersEntry.getValue().equals(request.getHeader(headersEntry.getKey()))) {
                    return null;
                }
            }
        }

        //pathParams
        Map pathParams = new HashMap();
        for (int i = 0; i < m.groupCount() && i < pathParamNames.size(); i++) {
            pathParams.put(pathParamNames.get(i), m.group(i + 1));
        }
        //formParams
        Map> formParams = null;

        //有文件上传
        MultipartParam multipartParam = null;
        if (multipartBuilder != null) {
            multipartParam = multipartBuilder.readMultipart(request);
        }

        RouteMatch routeMatch = null;
        Params params = null;
        Map fileParams = null;
        String jsonParams = null;
        String contentType = request.getContentType();
        try {
            if (contentType != null && contentType.toLowerCase().contains(ContentType.JSON.value())) {
                //从 queryString 取json
                String queryString = request.getQueryString();

                if (queryString != null && (httpMethod.equals(HttpMethod.GET) || httpMethod.equals(HttpMethod.DELETE)) && Jsoner.isJson(queryString)) {
                    jsonParams = queryString;

                } else {
                    jsonParams = getJson(request);
                    formParams = request.getQueryParams();
                }

                printMatchRoute(request.getContentType(), jsonParams, pathParams, formParams, null);
                params = parseJsonParams(jsonParams, pathParams, formParams);
            } else {
                formParams = request.getQueryParams();
                //print match route
                if (multipartParam != null) {
                    fileParams = multipartParam.getUploadedFiles();

                    if (formParams != null) {
                        formParams.putAll(multipartParam.getParams());
                    } else {
                        formParams = multipartParam.getParams();
                    }

                    printMatchRoute(request.getContentType(), null, pathParams, formParams, fileParams);
                    params = parseFormParams(pathParams, formParams, fileParams);
                } else {
                    printMatchRoute(request.getContentType(), null, pathParams, formParams, null);
                    params = parseFormParams(pathParams, formParams, new Hashtable());
                }
            }
        } catch (Exception e) {
            printMatchRoute(request.getContentType(), jsonParams, pathParams, formParams, fileParams);
            throwException(e);
        }
        routeMatch = new RouteMatch(pathPattern, restPath, extension, params, request, response);
        return routeMatch;
    }

    /**
     * 打印route信息
     *
     * @param pathParams path参数
     * @param formParams 其他参数
     * @param fileParams 文件参数
     */
    private void printMatchRoute(String contentType, String jsonParams, Map pathParams, Map> formParams, Map fileParams) {
        if (Constant.showRoute && logger.isInfoEnabled()) {
            //print route
            StringBuilder sb = new StringBuilder("\n\nMatch route ----------------- ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append(" ------------------------------");
            sb.append("\nResource     : ").append(resourceClass.getName()).append("(").append(resourceClass.getSimpleName()).append(".java:" + allLineNumbers[0] + ")");
            sb.append("\nMethod       : ").append(method.getName());
            sb.append("\nPathPattern  : ").append(httpMethod).append(" ").append(pathPattern);
            sb.append("\nContentType  : ").append(contentType);
            //print pathParams
            sb.append("\nPathParams   : ");
            if (pathParams != null && pathParams.size() > 0) {
                Set> paramsEntrySet = pathParams.entrySet();
                for (Map.Entry paramsEntry : paramsEntrySet) {
                    sb.append(paramsEntry.getKey()).append(" = {").append(paramsEntry.getValue()).append("}");
                    sb.append("  ");
                }
            }
            //print formParams
            if (formParams != null && formParams.size() > 0) {
                sb.append("\nFormParams   : ");
                List values;
                Set>> formParamsEntrySet = formParams.entrySet();
                for (Map.Entry> formParamsEntry : formParamsEntrySet) {
                    values = formParamsEntry.getValue();
                    if (values.size() >= 1) {
                        sb.append(formParamsEntry.getKey()).append(" = {").append(values.get(0)).append("}");
                    }
                    sb.append("  ");
                }
            }
            //print jsonParams
            if (jsonParams != null) {
                sb.append("\nJsonParams   : ").append(jsonParams);
            }

            //print fileParams
            if (fileParams != null && fileParams.size() > 0) {
                sb.append("\nFileParams   : ");
                UploadedFile value;
                Set> fileParamsEntrySet = fileParams.entrySet();
                for (Map.Entry fileParamsEntry : fileParamsEntrySet) {
                    value = fileParamsEntry.getValue();
                    sb.append(fileParamsEntry.getKey()).append(" = {").append(value.getOriginalFileName()).append("(").append(value.getContentType()).append(")}");
                    sb.append("  ");
                }
            }

            Type returnType = method.getGenericReturnType();
            sb.append("\nReturnType   : ").append(returnType);

            if (validators != null && validators.length > 0) {
                sb.append("\nValidators   : ");
                int i = 0;
                for (Validator validator : validators) {
                    if (i > 0)
                        sb.append("\n               ");
                    Class vc = validator.getClass();
                    sb.append(vc.getName()).append("(").append(vc.getSimpleName()).append(".java:").append(validsLineNumbers[i][0]).append(")");
                    i++;
                }
            }

            if (interceptors != null && interceptors.length > 0) {
                sb.append("\nInterceptors : ");
                int i = 0;
                for (Interceptor interceptor : interceptors) {
                    if (i > 0) {
                        sb.append("\n               ");
                    }
                    Class ic = interceptor.getClass();
                    sb.append(ic.getName()).append("(").append(ic.getSimpleName()).append(".java:").append(interceptorsLineNumbers[i][0]).append(")");
                    i++;
                }
            }

            sb.append("\n--------------------------------------------------------------------------------\n");
            logger.info(sb.toString());
        }
    }

    public String toString() {
        return httpMethod + " " + pathPattern + " " + Joiner.on(",").join(allParamNames);
    }

    public Class getResourceClass() {
        return resourceClass;
    }

    public Method getMethod() {
        return method;
    }

    public String getHttpMethod() {
        return httpMethod;
    }

    public String getPattern() {
        return pattern.pattern();
    }

    public String getPathPattern() {
        return pathPattern;
    }

    public String getStdPathPattern() {
        return stdPathPattern;
    }

    public List getPathParamNames() {
        return pathParamNames;
    }

    public List getAllParamNames() {
        return allParamNames;
    }

    public List> getAllParamTypes() {
        return allParamTypes;
    }

    public List getAllGenericParamTypes() {
        return allGenericParamTypes;
    }

    public Interceptor[] getInterceptors() {
        return interceptors;
    }

    public Validator[] getValidators() {
        return validators;
    }

    public int[] getAllLineNumbers() {
        return allLineNumbers;
    }
    // here comes the path pattern parsing logic
    // the code is pretty ugly with lot of cross dependencies, I tried to keep it performant, correct, and maintainable
    // not sure those goals are all achieved though

    public MultipartBuilder getMultipartBuilder() {
        return multipartBuilder;
    }

    public Map getHeaders() {
        return headers;
    }

    /**
     * 抛出异常
     *
     * @param throwable
     */
    public void throwException(Throwable throwable) {
        if (throwable instanceof WebException) {
            throw (WebException) throwable;
        } else {
            WebException exception = getWebException(throwable, 0);
            Throwable cause = throwable.getCause();
            if (cause != null) {
                logger.error("Route method invoke error.", cause);
            } else {
                logger.error("Route method invoke error.", throwable);
            }
            throw exception;
        }
    }

    private WebException getWebException(Throwable throwable, int deep) {
        WebException result = null;

        String message = throwable.getMessage();
        if (message == null) {
            Throwable cause = throwable.getCause();
            if (cause != null) {
                if (cause instanceof WebException) {
                    result = (WebException) cause;
                } else {
                    message = cause.getMessage();
                    if (message == null && !throwable.equals(cause) && deep < 100) {
                        result = getWebException(cause, ++deep);
                    }
                }
            }
        } else {
            if (throwable instanceof WebException) {
                result = (WebException) throwable;
            }
        }

        if (result == null) {
            result = new WebException(HttpStatus.INTERNAL_SERVER_ERROR, message);
        }
        return result;
    }

    /**
     * 获取json字符串
     *
     * @param request
     * @return
     */
    private String getJson(HttpRequest request) {
        String json = null;
        try {
            InputStream is = request.getContentStream();
            if (is != null) {
                json = StreamReader.readString(is);
            }
        } catch (IOException e) {
            String msg = "Could not read inputStream when contentType is '" + request.getContentType() + "'.";
            logger.error(msg, e);
            throw new WebException(msg);
        }
        return json;
    }

    /**
     * 获取所有的请求参数
     *
     * @return 所有参数
     */
    private Params parseFormParams(Map pathParams, Map> formParams, Map fileParams) throws IllegalAccessException, InstantiationException {
        Params params = new Params();
        int i = 0;
        Class paramType = null;
        List valueArr = null;
        //判断范型类型
        Type[] typeArguments;

        Class keyTypeClass;
        Class valueTypeClass;
        for (String name : allParamNames) {
            paramType = allParamTypes.get(i);

            //path里的参数
            if (pathParamNames.contains(name)) {
                if (paramType == String.class) {
                    params.set(name, pathParams.get(name));
                } else
                    params.set(name, ModelDeserializer.parse(pathParams.get(name), paramType));
            } else {//其他参数
                if (paramType == UploadedFile.class) {
                    params.set(name, fileParams.remove(name));
                } else if (paramType == Map.class) {
                    typeArguments = ((ParameterizedType) allGenericParamTypes.get(i)).getActualTypeArguments();
                    if (typeArguments.length >= 2) {
                        keyTypeClass = (Class) typeArguments[0];
                        valueTypeClass = (Class) typeArguments[1];
                        if (keyTypeClass == String.class && valueTypeClass == UploadedFile.class) {
                            params.set(name, fileParams);
                        } else {
                            valueArr = formParams.remove(name);
                            params.set(name, parseString(paramType, valueArr));
                        }
                    } else {
                        valueArr = formParams.remove(name);
                        params.set(name, parseString(paramType, valueArr));
                    }
                } else {
                    valueArr = formParams.remove(name);
                    params.set(name, parseString(paramType, valueArr));
                }
            }
            i++;
        }
        String name;
        if (formParams.size() > 0) {
            for (Map.Entry> formEntry : formParams.entrySet()) {
                name = formEntry.getKey();
                if (!params.containsName(name)) {
                    valueArr = formEntry.getValue();
                    if (valueArr != null && valueArr.size() > 0) {
                        params.set(name, valueArr.get(0));
                    } else {
                        params.set(name, null);
                    }
                }
            }
        }
        if (fileParams.size() > 0) {
            for (Map.Entry fileEntry : fileParams.entrySet()) {
                name = fileEntry.getKey();
                if (!params.containsName(name)) {
                    params.set(fileEntry.getKey(), fileEntry.getValue());
                }
            }
        }
        return params;
    }


    /**
     * 转换string类型参数
     *
     * @param paramType
     * @param valueArr
     */
    private Object parseString(Class paramType, List valueArr) throws InstantiationException, IllegalAccessException {
        String value;
        Object result = null;
        if (valueArr != null && valueArr.size() > 0) {
            //不支持数组参数
            value = valueArr.get(0);
            if (paramType == String.class) {
                result = value;
            } else {
                //转换为对应的对象类型
                result = ModelDeserializer.parse(value, paramType);
            }
        }
        return result;
    }


    /**
     * 获取所有以application/json方式提交的数据
     *
     * @param json json字符串
     * @return 所有参数
     */
    private Params parseJsonParams(String json, Map pathParams, Map> formParams) throws IllegalAccessException, InstantiationException {
        Params params = new Params();

        int i = 0;
        Class paramType = null;

        //只有一个参数时 直接把该参数 放入方法
        boolean oneParamParse = false;
        int paramSize = allParamNames.size() - pathParamNames.size();
        if (Constant.oneParamParse) {
            oneParamParse = paramSize == 1;
        }

        Object obj = null;
        List valueArr = null;

        boolean hasJsonParam = null != json && !"".equals(json);
        Object receiveParams = null;
        if (hasJsonParam && !oneParamParse) {
            if (json.startsWith("\"") || json.startsWith("{") || json.startsWith("[")) {
                receiveParams = Jsoner.toObject(json);
            } else {
                receiveParams = Jsoner.toObject("\"" + json + "\"");
            }
            hasJsonParam = receiveParams != null;
        }
        for (String name : allParamNames) {
            paramType = allParamTypes.get(i);

            //path里的参数
            if (pathParamNames.contains(name)) {
                if (paramType == String.class) {
                    params.set(name, pathParams.get(name));
                } else {
                    params.set(name, Jsoner.toObject(pathParams.get(name), paramType));
                }
            } else {//其他参数
                if (hasJsonParam) {
                    if (oneParamParse) {
                        //转换对象到指定的类型
                        params.set(name, parse(allGenericParamTypes.get(i), paramType, ModelDeserializer.parse(json, paramType)));
                    } else {
                        if (receiveParams instanceof Map) {
                            obj = ((Map) receiveParams).remove(name);

                            if (obj != null) {
                                if (paramType == String.class) {
                                    params.set(name, obj.toString());
                                } else {
                                    //转换对象到指定的类型
                                    params.set(name, parse(allGenericParamTypes.get(i), paramType, obj));
                                }
                            }
                        }
                    }
                }
                //没有获取到的参数设置为空
                if (!params.containsName(name)) {
                    if (formParams != null && formParams.size() > 0) {
                        valueArr = formParams.remove(name);
                    }
                    params.set(name, parseString(paramType, valueArr));
                }
            }

            i++;
        }

        String name;
        if (hasJsonParam && receiveParams instanceof Map && !oneParamParse) {
            for (Map.Entry receiveEntry : ((Map) receiveParams).entrySet()) {
                name = receiveEntry.getKey();
                if (!params.containsName(name)) {
                    params.set(receiveEntry.getKey(), receiveEntry.getValue());
                }
            }
        }

        if (formParams != null && formParams.size() > 0) {
            for (Map.Entry> formEntry : formParams.entrySet()) {
                name = formEntry.getKey();
                if (!params.containsName(name)) {
                    valueArr = formEntry.getValue();
                    if (valueArr != null && valueArr.size() > 0) {
                        params.set(name, valueArr.get(0));
                    } else {
                        params.set(name, null);
                    }
                }
            }
        }
        return params;
    }

    /**
     * 把参数转到对应的类型
     *
     * @param paramType
     * @param obj
     */
    private Object parse(Type genericParamType, Class paramType, Object obj) throws InstantiationException, IllegalAccessException {
        Class keyTypeClass;
        Class paramTypeClass;
        List list;
        List newlist;
        List blist;
        List newblist;

        Set set;
        Set newset;
        Set bset;
        Set newbset;
        Map map;
        Set> mapEntry;
        Map newMap;

        Object result = null;
        if (obj != null) {
            if (Map.class.isAssignableFrom(paramType)) {
                keyTypeClass = (Class) ((ParameterizedType) genericParamType).getActualTypeArguments()[0];
                paramTypeClass = (Class) ((ParameterizedType) genericParamType).getActualTypeArguments()[1];
                map = (Map) obj;
                newMap = new HashMap();
                mapEntry = map.entrySet();
                for (Map.Entry entry : mapEntry) {
                    newMap.put(ModelDeserializer.parse(entry.getKey(), keyTypeClass), ModelDeserializer.parse(entry.getValue(), paramTypeClass));
                }
                result = newMap;
            } else if (Collection.class.isAssignableFrom(paramType)) {
                paramTypeClass = (Class) ((ParameterizedType) genericParamType).getActualTypeArguments()[0];

                if (List.class.isAssignableFrom(paramType)) {
                    //Entity类型
                    if (Entity.class.isAssignableFrom(paramTypeClass)) {
                        list = (List) obj;
                        newlist = new ArrayList();
                        for (JSONObject jo : list) {
                            newlist.add(ModelDeserializer.deserialze(jo, paramTypeClass));
                        }
                        result = newlist;
                    } else {
                        blist = (List) obj;
                        if (String.class == paramTypeClass) {
                            newblist = new ArrayList();
                            for (Object o : blist) {
                                newblist.add(o.toString());
                            }
                        } else {
                            newblist = new ArrayList();
                            for (Object o : blist) {
                                if (paramTypeClass.isAssignableFrom(o.getClass())) {
                                    newblist.add(o);
                                } else {
                                    newblist.add(ModelDeserializer.parse(o, paramTypeClass));
                                }
                            }
                        }
                        result = newblist;
                    }
                } else if (Set.class.isAssignableFrom(paramType)) {
                    //Entity
                    if (Entity.class.isAssignableFrom(paramTypeClass)) {
                        set = (Set) obj;
                        newset = new HashSet();
                        for (JSONObject jo : set) {
                            newset.add(ModelDeserializer.deserialze(jo, paramTypeClass));
                        }
                        result = newset;
                    } else {
                        bset = (Set) obj;
                        if (String.class == paramTypeClass) {
                            newbset = new HashSet();
                            for (Object o : bset) {
                                newbset.add(o.toString());
                            }
                        } else {
                            newbset = new HashSet();
                            for (Object o : bset) {
                                if (paramTypeClass.isAssignableFrom(o.getClass())) {
                                    newbset.add(o);
                                } else {
                                    newbset.add(ModelDeserializer.parse(o, paramTypeClass));
                                }
                            }
                        }
                        result = newbset;
                    }
                }
            } else {
                result = ModelDeserializer.parse(obj, paramType);
            }
        }
        return result;
    }


    private static interface PathParserCharProcessor {
        void handle(int curChar, PathPatternParser pathPatternParser);

        void end(PathPatternParser pathPatternParser);
    }

    private static final class PathPatternParser {
        final int length;
        final String pathPattern;
        int offset = 0;
        PathParserCharProcessor processor = regularCharPathParserCharProcessor;
        List pathParamNames = new ArrayList();
        StringBuilder patternBuilder = new StringBuilder();
        StringBuilder stdPathPatternBuilder = new StringBuilder();

        private PathPatternParser(String pathPattern) {
            this.length = pathPattern.length();
            this.pathPattern = pathPattern;
        }

        void parse() {
            while (offset < length) {
                int curChar = pathPattern.codePointAt(offset);

                processor.handle(curChar, this);

                offset += Character.charCount(curChar);
            }
            processor.end(this);
        }
    }

    private static final class CurlyBracesPathParamPathParserCharProcessor implements PathParserCharProcessor {
        private int openBr = 1;
        private boolean inRegexDef;
        private StringBuilder pathParamName = new StringBuilder();
        private StringBuilder pathParamRegex = new StringBuilder();


        public void handle(int curChar, PathPatternParser pathPatternParser) {
            if (curChar == '}') {
                openBr--;
                if (openBr == 0) {
                    // found matching brace, end of path param

                    if (pathParamName.length() == 0) {
                        // it was a mere {}, can't be interpreted as a path param
                        pathPatternParser.processor = regularCharPathParserCharProcessor;
                        pathPatternParser.patternBuilder.append("{}");
                        pathPatternParser.stdPathPatternBuilder.append("{}");
                        return;
                    }

                    // only the opening paren
                    checkArgument(pathParamRegex.length() != 1, "illegal path parameter definition '%s' at offset %d - custom regex must not be empty",
                            pathPatternParser.pathPattern, pathPatternParser.offset);


                    if (pathParamRegex.length() == 0) {
                        // use default regex
                        pathParamRegex.append(PARAM_PATTERN);
                    } else {
                        // close paren for matching group
                        pathParamRegex.append(")");
                    }

                    pathPatternParser.processor = regularCharPathParserCharProcessor;
                    pathPatternParser.patternBuilder.append(pathParamRegex);
                    pathPatternParser.stdPathPatternBuilder.append("{").append(pathParamName).append("}");
                    pathPatternParser.pathParamNames.add(pathParamName.toString());
                    return;
                }
            } else if (curChar == '{') {
                openBr++;
            }

            if (inRegexDef) {
                pathParamRegex.appendCodePoint(curChar);
            } else {
                if (curChar == ':') {
                    // we were in path name, the column marks the separator with the regex definition, we go in regex mode
                    inRegexDef = true;
                    pathParamRegex.append("(");
                } else {

                    //only letters are authorized in path param name
                    checkArgument(Character.isLetterOrDigit(curChar), "illegal path parameter definition '%s' at offset %d" +
                                    " - only letters and digits are authorized in path param name",
                            pathPatternParser.pathPattern, pathPatternParser.offset);

                    pathParamName.appendCodePoint(curChar);
                }
            }
        }


        public void end(PathPatternParser pathPatternParser) {
        }
    }

    private static final class SimpleColumnBasedPathParamParserCharProcessor implements PathParserCharProcessor {
        private StringBuilder pathParamName = new StringBuilder();

        public void handle(int curChar, PathPatternParser pathPatternParser) {
//      if (!Character.isLetterOrDigit(curChar) && curChar != '_') {
            if (curChar == '/') {
                pathPatternParser.patternBuilder.append(PARAM_PATTERN);
                pathPatternParser.stdPathPatternBuilder.append("{").append(pathParamName).append("}");
                pathPatternParser.pathParamNames.add(pathParamName.toString());
                pathPatternParser.processor = regularCharPathParserCharProcessor;
                pathPatternParser.processor.handle(curChar, pathPatternParser);
            } else {
                pathParamName.appendCodePoint(curChar);
            }
        }


        public void end(PathPatternParser pathPatternParser) {
            pathPatternParser.patternBuilder.append(PARAM_PATTERN);
            pathPatternParser.stdPathPatternBuilder.append("{").append(pathParamName).append("}");
            pathPatternParser.pathParamNames.add(pathParamName.toString());
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy